Смешивание Qt с STL и Boost - есть ли какие-то мосты, чтобы упростить это?

Есть ли какие-то мосты, чтобы сделать смешивание Qt с STL и Boost максимально простым и плавным?

Это продолжение смешивания Qt и Boost, где не было дано никаких конкретных ответов, как это сделать.


person Piotr Dobrogost    schedule 11.05.2009    source источник
comment
Что именно вас беспокоит? Теоретически не должно быть так много областей, в которых должны сосуществовать и boost, и Qt.   -  person Kena    schedule 11.05.2009
comment
У меня еще не было никаких проблем, так как я только знакомлюсь с Qt, но, имея такое большое совпадение между Qt, STL и Boost, я уверен, что есть много мест, где требуется какая-то маршалинг. Это то же самое, что и с .NET и C++; вот почему M$ придумал библиотеку маршалинга. Я пытаюсь быть готовым к вещам, которых не могу избежать.   -  person Piotr Dobrogost    schedule 11.05.2009
comment
Во-первых, компания называется Microsoft, сокращенно MS. Только 13-летние сценаристы называют их M$. Во-вторых, взаимодействие .NET/C++ — это совершенно другой зверь, поскольку вы взаимодействуете между совершенно разными платформами, управляемым и неуправляемым кодом. QT и Boost — это библиотеки C++, работающие в одном процессе, с использованием одной и той же среды выполнения и всего остального. Никакой маршаллинг там не нужен.   -  person jalf    schedule 11.05.2009
comment
@jalf Если вы не возражаете, я буду продолжать использовать аббревиатуру, которая мне нравится. Спасибо.   -  person Piotr Dobrogost    schedule 11.05.2009
comment
@jalf Кстати, взгляните на сортировку в Википедии.   -  person Piotr Dobrogost    schedule 11.05.2009
comment
@jalf: это не просто детские скрипты: farm1.static.flickr.com/87/240803829_9212773615_o .png Я тоже в этом виноват...   -  person Zifre    schedule 12.05.2009


Ответы (3)


Какие мосты вам нужны?

Вы можете использовать все классы контейнеров Qt со стандартными алгоритмами. В большинстве случаев я предпочитаю контейнерные классы Qt, потому что я уверен, что они используют идиому копирования при записи (операция с постоянным временем). Функция Qt foreach создает копию контейнера, поэтому хорошо, что вы точно знаете, что это операция с постоянным временем.

Если механизм сигнального слота Qt работает медленно, вы можете переключиться на альтернативу повышения. Отличительной особенностью Qt signal/slot является связь сигнал/слот между двумя потоками.

QtConcurrent отлично работает с BOOST.Lambda


Для «общих» дочерних и родительских отношений я использую эту вспомогательную функцию.

template <class Object>
static boost::shared_ptr<Object> makeSharedObject()
{
    using namespace boost;
    using namespace boost::lambda;
    return boost::shared_ptr<Object>( 
        new Object(),
        bind( &Object::deleteLater, _1 ) );
}

Контейнеры Qt не поддерживаются Boost.serialize, вам придется самостоятельно писать функции сериализации. Мне бы хотелось создать мост между классами потоковой передачи Qt и Boost.archive.

Вот мой шаблон сериализации QList, с остальными вы можете разобраться...

///\file document is based on "boost/serialization/list.hpp"

namespace boost { 
    namespace serialization {

        //---------------------------------------------------------------------------
        /// Saves a QList object to a collection 
        template<class Archive, class U >
        inline void save(Archive &ar, const QList< U > &t, const uint /* file_version */ )
        {
            boost::serialization::stl::save_collection< Archive, QList<U> >(ar, t);
        }

        //---------------------------------------------------------------------------
        /// Loads a QList object from a collection 
        template<class Archive, class U>
        inline void load(Archive &ar, QList<U > &t, const uint /* file_version */ )
        {
                boost::serialization::stl::load_collection< 
                    Archive, 
                    QList<U>, 
                    boost::serialization::stl::archive_input_seq<Archive, QList<U> >,
                    boost::serialization::stl::no_reserve_imp< QList<U> > >(ar, t);
        }

        //---------------------------------------------------------------------------
        /// split non-intrusive serialization function member into separate
        /// non intrusive save/load member functions
        template<class Archive, class U >
        inline void serialize(Archive &ar, QList<U> &t, const uint file_version )
        {
            boost::serialization::split_free( ar, t, file_version);
        }

    } // namespace serialization
} // namespace boost

BOOST_SERIALIZATION_COLLECTION_TRAITS(QList)

Если вы хотите, чтобы Boost.Bind обрабатывал QPointer как обычный указатель (например, shared_ptr):

namespace boost {

    template<typename T> T * get_pointer(QPointer<T> const& qPointer)
    {
        return qPointer;
    }
}

Использование QIODevice там, где требуется std::stream

namespace boost {
    namespace iostreams {

        class IoDeviceSource 
        {
        public:
            typedef char char_type;
            typedef source_tag category;

            explicit IoDeviceSource(QIODevice& source) 
                : m_source(source) 
            {
            }

            std::streamsize read(char* buffer, std::streamsize n)
            {
                return return m_source.read(buffer, n);
            }   
        private:
            QIODevice& m_source;
        };

        class IoDeviceSink {

        public:
            typedef char char_type;
            typedef sink_tag category;

            explicit IoDeviceSink(QIODevice& sink)
                : m_sink(sink)
            {
            }

            std::streamsize write(const char_type* buffer, std::streamsize n) 
            {
                return m_sink.write(buffer, n);
            }

        private:
            QIODevice &m_sink;
        };

        class IoDeviceDevice {

        public:
            typedef char char_type;
            typedef seekable_device_tag category;

            explicit IoDeviceDevice(QIODevice& device)
                :m_device(device) {
            }

            std::streamsize write(const char_type *buffer, std::streamsize n)
            {
                return m_device.write(buffer, n);
            }

            std::streamsize read(char* buffer, std::streamsize n)
            {
                return m_device.read(buffer, n);
            }

            stream_offset seek(stream_offset off, std::ios_base::seekdir way)
            {
                using namespace std;
                stream_offset next(0);

                if(way==ios_base::beg)
                {
                    next = m_device.pos();
                } 
                else if(way==ios_base::cur)
                {
                    next = m_device.pos() + offset;
                } 
                else if(way==ios_base::end)
                {
                    next = m_device.size() -1 + offset;
                }
                else
                {
                    throw ios_base::failure("bad seek direction");
                }

                if( !m_device.seek(next) )
                {
                    throw ios_base::failure("bad seek offset");
                }
                return m_device.pos();
            }

        private:    
            QIODevice &m_device;
        };
    }
}

Пример

#include <iostream>
#include <QFile>
#include <boost/iostreams/stream.hpp>
#include "iodevicestream.h"

int main(int argc, char *argv[])
{
    namespace io = boost::iostreams;

    QVector<int> data;

    QFile fl("temp.bin");
    fl.open(QIODevice::ReadWrite);
    io::stream<io::IoDeviceDevice> inoutput( fl );  

    std::copy(data.begin(), data.end(), std::ostream_iterator<int>(inoutput, "\n"));
    inoutput.flush();
    inoutput.seekg(0, std::ios_base::beg);
    std::cout << inoutput;
    return 0;
}
person TimW    schedule 13.05.2009
comment
@TimW Пока это лучший ответ ... Спасибо за реальный код. Зная, насколько популярен Boost, я надеюсь, что команда Qt сделает такие мосты частью фреймворка, чтобы избавить людей от изобретения велосипеда. Я думаю, что это также помогло бы более быстрому внедрению Qt разработчиками, уже работающими с Boost. Это можно рассматривать как очень важный фактор популярности Qt в определенных кругах C++. - person Piotr Dobrogost; 17.05.2009
comment
Не следует ли в случае с way==ios_base::beg в seek установить next в offset, а не m_device.pos()? - person Adam Badura; 06.05.2013

В чем именно заключается проблема?
Вы можете игнорировать все классы коллекций Qt, если хотите, и использовать эквиваленты STL.
Точно так же вы можете использовать кросс-платформенные файловые/сетевые библиотеки Boost.

Основная причина использования собственного Qt, вероятно, заключается в том, что boost не обязательно широко доступен, особенно на мобильных устройствах. Некоторые из библиотек Boost немного сложнее в использовании, чем библиотеки Qt для простых задач.

person Martin Beckett    schedule 11.05.2009
comment
@mgb Вопрос не в том, какой из них выбрать и почему, а в том, что делать при одновременном использовании обоих. См. ответ TimW, который примерно соответствует тому, на что я надеялся. - person Piotr Dobrogost; 17.05.2009
comment
ОК, я вижу, вы можете отредактировать вопрос, чтобы перефразировать его. - person Martin Beckett; 18.05.2009
comment
@mgb Пример: у меня есть базовый класс AbstractImage, который должен реализовать функцию загрузки (QIODevice*). Подкласс ImageEXR, который использует библиотеку openEXR для загрузки изображений EXR. Но загрузка openEXR использует istream в качестве входных данных и не знает о Qt. - person galinette; 29.05.2013

В общем, вы будете лучше при использовании QT, если будете придерживаться классов QT Collection, а не STL. В Qt, STL или Boost как таковых нет ничего, что мешало бы их использованию друг в друге.

Вы должны быть осторожны при использовании интеллектуальных указателей. QT имеет родительские/дочерние отношения, которые могут позаботиться об уничтожении объектов, освобождении объектов, когда они находятся под контролем Qt, что приведет к сбою.

person Harald Scheirich    schedule 11.05.2009
comment
совершенно безопасно удалять объект Qt. В деструкторе QObject он отменит регистрацию в дочернем списке своего родителя. Никакого сбоя. - person Evan Teran; 12.05.2009
comment
@Evan, есть несколько подводных камней... doc.qtsoftware.com/4.5/objecttrees.html внизу. - person Idan K; 12.05.2009
comment
У меня были проблемы с этим в прошлом. Это может быть связано с проблемой заказа, отмеченной в приведенном выше документе. - person Harald Scheirich; 12.05.2009
comment
@Evan Это не так безопасно, если родитель объекта удаляет QObject, но интеллектуальный указатель (не поддерживающий Qt), который думает, что он отвечает за удаление QObject, не знает, что QObject был удален из-под него, и поэтому позже пытается удалить его во второй раз... :( - person Jeremy Friesner; 03.06.2012
comment
@JeremyFriesner: Даже у интеллектуальных указателей Qt есть эта проблема: blog.codef00.com/2011/12/15/not-so-much-fun-with-qsharedpointer - person Evan Teran; 04.06.2012