【问题标题】:Mixing Qt with STL and Boost - are there any bridges to make it easy?将 Qt 与 STL 和 Boost 混合使用 - 是否有任何桥梁可以让它变得简单?
【发布时间】:2010-10-25 07:09:40
【问题描述】:

是否有任何桥梁可以使 Qt 与 STL 和 Boost 的混合尽可能无缝和容易?

这是Mixing Qt and Boost 的后续行动,其中没有给出如何完成此任务的具体答案。

【问题讨论】:

  • 您到底关心什么?从理论上讲,boost 和 Qt 需要共存的领域应该不会太多。
  • 我还没有遇到任何问题,因为我刚刚开始了解 Qt,但是 Qt、STL 和 Boost 之间有很多重叠我敢肯定有很多地方需要某种编组是需要的。这与 .NET 和 C++ 相同;这就是 M$ 提出编组库的原因。我正在努力为无法避免的事情做好准备。
  • 首先,这家公司叫微软,简称MS。只有 13 岁的脚本小子称他们为 M$。其次,.NET/C++ 互操作是完全不同的野兽,因为您在完全不同的平台、托管和非托管代码之间进行通信。 QT 和 Boost 都是 C++ 库,在同一个进程中运行,使用相同的运行时和一切。那里不需要编组。
  • @jalf 如果你不介意我会继续使用我喜欢的首字母缩写词。谢谢。
  • @jalf:这不仅仅是脚本小子:farm1.static.flickr.com/87/240803829_9212773615_o.png 我也对此感到内疚......

标签: c++ qt boost stl


【解决方案1】:

您需要哪些桥梁?

您可以将所有 Qt 容器类与标准算法一起使用。 大多数时候我更喜欢 Qt 容器类,因为我确信它们使用写时复制习语(恒定时间操作)。 Qt 的 foreach 函数会创建容器的副本,因此您可以确定它是一个恒定时间操作,这很好。

如果 Qt 信号槽机制变慢,您可以切换到 boost 替代方案。 Qt 信号/槽的伟大之处在于两个线程之间的信号/槽连接。

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 ) );
}

Boost.serialize 不支持 Qt 容器,您必须自己编写序列化函数。 我希望在 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;
    }
}

在需要std::stream 的地方使用QIODevice

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;
}

【讨论】:

  • @TimW 这是迄今为止最好的答案......感谢真实世界的代码。知道 Boost 有多受欢迎,我希望 Qt 团队将这些桥梁作为框架的一部分,以避免人们重新发明轮子。我认为这也将有助于在已经使用 Boost 的开发人员中更快地采用 Qt。这可能被视为 Qt 在某些 C++ 圈子中受欢迎的一个非常重要的因素。
  • 不应该将seek 中的way==ios_base::beg 设置为nextoffset 而不是m_device.pos()
【解决方案2】:

究竟是什么问题?
如果需要,可以忽略所有 Qt 集合类并使用 STL 等效项。
同样,您可以使用 Boost 的跨平台文件/网络库。

使用 Qt 自己的主要原因可能是 boost 不一定广泛可用,尤其是在移动设备上。对于简单的任务,Boost 的一些库比 Qt 的库更复杂一些。

【讨论】:

  • @mgb 这不是关于选择哪个以及为什么选择的问题,而是关于同时使用两者时该怎么做的问题。请参阅 TimW 的答案,这大致是我所希望的。
  • 好的,我明白了,您可能需要编辑问题以重新表述它。
  • @mgb 示例:我有一个 AbstractImage 基类,它必须实现 load(QIODevice*) 函数。一个 ImageEXR 子类,它使用 openEXR 库来加载 EXR 图像。但是 openEXR 加载使用 istream 作为输入并且不了解 Qt。
【解决方案3】:

一般来说,如果你坚持使用 QT Collection 类而不是我们的 STL,那么使用 QT 会更好。在 Qt、STL 或 Boost 中,没有任何东西本身会排除在彼此之间使用 then 的可能性。

使用智能指针时必须小心 QT 具有可以处理对象销毁的父/子关系,当对象在 Qt 控制下时释放对象会导致崩溃。

【讨论】:

  • 删除一个 Qt 对象是完全安全的。在 QObject 的析构函数中,它将从其父子列表中注销自己。完全没有崩溃。
  • @Evan,有一些陷阱...底部有doc.qtsoftware.com/4.5/objecttrees.html
  • 我过去遇到过这个问题。这可能是由于上述文档中提到的排序问题。
  • @Evan 如果对象的父级删除 QObject 则不是那么安全,但是认为它负责删除 QObject 的(非 Qt 感知)智能指针不知道 QObject 有已从其下方删除,因此稍后尝试再次将其删除... :(
  • @JeremyFriesner:即使是 Qt 的智能指针也有这个问题:blog.codef00.com/2011/12/15/not-so-much-fun-with-qsharedpointer
猜你喜欢
  • 2010-09-26
  • 1970-01-01
  • 2014-10-08
  • 2010-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多