11

我正在尝试序列化指向多态类的指针Shape。所以我需要使用BOOST_CLASS_EXPORT来为每个子类定义一个 GUID。问题:放在哪里?

让我先展示一个最小的测试用例:

形状.hpp

#include <boost/serialization/access.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>

class Shape {
    friend class boost::serialization::access;

    template<typename Archive>
    void serialize(Archive &ar, unsigned int const version) {
        // nothing to do
    }

    public:
        virtual ~Shape() { }
};

class Rect : public Shape {
    friend class boost::serialization::access;

    template<typename Archive>
    void serialize(Archive &ar, unsigned int const version) {
        ar & boost::serialization::base_object<Shape>(*this);
    }

    public:
        virtual ~Rect() { }
};

#ifdef EXPORT_IN_HEADER
    BOOST_CLASS_EXPORT(Rect)
#endif

导出.cpp

#include <boost/serialization/export.hpp>
#include "shapes.hpp"

#ifdef EXPORT_IN_OBJECT
    BOOST_CLASS_EXPORT(Rect)
#endif

主文件

#include <iostream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/export.hpp>
#include "shapes.hpp"

#ifdef EXPORT_IN_MAIN
    BOOST_CLASS_EXPORT(Rect)
#endif

int main() {
    Shape *shape = new Rect();
    boost::archive::text_oarchive ar(std::cout);
    ar << shape;
}

在 gcc 上,我用

g++ -omain main.cpp export.cpp -Wl,-Bstatic -lboost_serialization-mt -Wl,-Bdynamic -DEXPORT_IN_XXX

在这里,export.cpp可能看起来有点傻。在我的实际情况中,它包含一个使用 PIMPL 习语的封闭类,并尝试序列化其(多态)Shape实现。重要的一点是:BOOST_CLASS_EXPORT可能与调用序列化的代码位于不同的目标文件中。

那么问题来了:在哪里使用BOOST_CLASS_EXPORT?我有三个选项,可以使用EXPORT_IN_XXX宏启用。

  1. EXPORT_IN_MAIN有效,但不是我想要的。调用序列化的代码不需要知道 PIMPL 类的实现细节。

  2. EXPORT_IN_OBJECT编译,但不起作用:它导致boost::archive::archive_exception带有消息unregistered void cast。根据文档,这应该通过boost::serialization::base_object像我一样使用序列化基类来解决,但这没有帮助。

  3. EXPORT_IN_HEADER甚至不编译。宏BOOST_CLASS_EXPORT扩展为模板特化(我们希望在头文件中),但也扩展为其中静态成员的定义。所以我得到一个关于 a 的链接器错误multiple definition of 'boost::archive::detail::init_guid<Rect>::guid_initializer'

如果重要的话,我正在使用 g++ 4.4.3 和 Boost 1.40。

4

6 回答 6

9

Boost.Serialization 文档(1.44.0)的导出类序列化声明如下:


BOOST_CLASS_EXPORT在包含任何归档类头文件的同一源模块中,将实例化代码 [...]

请注意,此功能的实现要求 BOOST_CLASS_EXPORT宏出现在后面并包含要为其实例化代码的任何存档类标头。因此,使用 BOOST_CLASS_EXPORT的代码如下所示:

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
... // other archives

#include "a.hpp" // header declaration for class a
BOOST_CLASS_EXPORT(a)
... // other class headers and exports

[...] 包含BOOST_CLASS_EXPORT在“a.hpp”标头本身中,就像对其他序列化特征所做的那样,将难以或不可能遵循上述关于在 BOOST_CLASS_EXPORT调用之前包含存档标头的规则。这可以通过 BOOST_CLASS_EXPORT_KEY在头声明和BOOST_CLASS_EXPORT_IMPLEMENT类定义文件中使用来最好地解决。


于 2010-11-04T07:37:31.593 回答
4

我最终将所有序列化代码放在s11n.h调用序列化的 CPP 文件中包含的标头中。本质上,EXPORT_IN_MAIN我在上面勾勒的场景,但BOOST_CLASS_EXPORT宏调用在不同的文件中。

这只适用于只有一个编译单元包含s11n.h,当然,所以虽然它现在有效,但它不是真正的解决方案......

于 2010-10-20T19:40:36.863 回答
2

您可以使用 EXPORT_IN_OBJECT 但包含 BOOST_CLASS_EXPORT 的文件还必须包含所有计划使用的归档 hpp 文件。

这是因为 BOOST_CLASS_EXPORT 宏注册了它认为您将使用的每个存档的派生类型信息(根据您包含的存档隐式确定。)

在您的示例中,使用 EXPORT_IN_OBJECT 但还将 #include 添加到 export.cpp。

在我们的代码中,我们创建了 archives.hpp,其中包含我们使用的档案并将其包含在我们需要使用 BOOST_CLASS_EXPORT 的任何地方。(这样我们就有了一份正式的档案清单。)

不利的一面是,当我们决定使用新的归档类型时,我们需要重新构建所有内容,但我们发现它比多态归档支持更容易使用。

于 2010-11-03T20:42:17.393 回答
1

看看这个旧线程。

http://lists.boost.org/boost-users/2005/01/9390.php

于 2010-08-10T18:52:04.177 回答
0

您可以为每个 .cpp 使用唯一的 BOOST_CLASS_EXPORT_GUID() 并将其仅添加到 .cpp 中。不是.h

于 2014-03-27T14:54:09.933 回答
0

这个问题让我发疯,直到我意识到我的基类不是多态的。换句话说,它从未在任何地方使用过关键字“virtual”。因为我不需要多态行为。

这是我修复它的方法:

  1. 我只是在我的基类中的某个随机方法上添加了关键字“virtual”。
  2. 在派生类的 .cpp 文件中,我添加了以下内容:

    #include <boost/serialization/export.hpp>
    BOOST_CLASS_EXPORT(testnamespace::derivedclass)
    

这就是我必须做的。

于 2014-08-07T23:17:22.217 回答