在哪里放置 BOOST_CLASS_EXPORT 进行 boost::serialization?

发布于 2024-09-12 19:22:08 字数 2775 浏览 4 评论 0原文

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

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

shapes.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

export.cpp

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

#ifdef EXPORT_IN_OBJECT
    BOOST_CLASS_EXPORT(Rect)
#endif

ma​​in.cpp

#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

Here, 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 扩展为模板专业化(我们希望将其放在头文件中),而且还扩展为其中静态成员的定义。因此,我收到关于“boost::archive::detail::init_guid::guid_initializer”的多个定义的链接器错误。

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

I'm trying to serialize a pointer to a polymorphic class Shape. So I need to use the BOOST_CLASS_EXPORT macro to define a GUID for each subclass. The problem: where to put it?

Let me show a minimal test case first:

shapes.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

export.cpp

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

#ifdef EXPORT_IN_OBJECT
    BOOST_CLASS_EXPORT(Rect)
#endif

main.cpp

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

On gcc, I compile these with

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

Here, export.cpp may look a bit silly. In my actual situation, it contains an enclosing class that uses the PIMPL idiom, and tries to serialize its (polymorphic) Shape implementation. The important point is: the BOOST_CLASS_EXPORT could be in a different object file than the code that invokes the serialization.

So here's the problem: where to use BOOST_CLASS_EXPORT? I have three options, which can be enabled using the EXPORT_IN_XXX macros.

  1. EXPORT_IN_MAIN works, but is not what I want. The code invoking the serialization should not need to know about the implementation details of the PIMPL class.

  2. EXPORT_IN_OBJECT compiles, but does not work: it results in a boost::archive::archive_exception with the message unregistered void cast. According to the documentation, this should be solved by serializing base classes using boost::serialization::base_object, like I did, but it doesn't help.

  3. EXPORT_IN_HEADER does not even compile. The macro BOOST_CLASS_EXPORT expands to a template specialization (which we'd like to be in the header file), but also to the definitiof of a static member therein. So I get a linker error about a multiple definition of 'boost::archive::detail::init_guid<Rect>::guid_initializer'.

If it matters, I'm using g++ 4.4.3 and Boost 1.40.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

以可爱出名 2024-09-19 19:22:08

导出 Boost 的类序列化。序列化文档 (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_IMPLMENT
类定义文件。


Exporting Class Serialization of the Boost.Serialization docs (1.44.0) states the following:


BOOST_CLASS_EXPORT in the same
source module that includes any of the
archive class headers will instantiate
code [...]

Note that the implemenation of this
functionality requires that the
BOOST_CLASS_EXPORT macro appear
after and the inclusion of any archive
class headers for which code is to be
instantiated. So, code that uses
BOOST_CLASS_EXPORT will look like
the following:

#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

[...] Including BOOST_CLASS_EXPORT in
the "a.hpp" header itself as one would
do with other serialization traits
will make it difficult or impossible
to follow the rule above regarding
inclusion of archive headers before
BOOST_CLASS_EXPORT is invoked. This
can best be addressed by using
BOOST_CLASS_EXPORT_KEY in the header
declarations and BOOST_CLASS_EXPORT_IMPLEMENT in the
class definition file.


旧故 2024-09-19 19:22:08

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

当然,只有一个编译单元包含 s11n.h 时,这才有效,所以虽然它目前有效,但它不是真正的解决方案......

I ended up putting all the serialization code in a header s11n.h that is included from the CPP file that invokes the serialization. Essentially, the EXPORT_IN_MAIN scenario I sketched above, but with the BOOST_CLASS_EXPORT macro invocations in a different file.

This only works as long as only one compilation unit includes s11n.h, of course, so although it works for now, it's no real solution...

鹿! 2024-09-19 19:22:08

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

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

在您的示例中,使用 EXPORT_IN_OBJECT 但还要添加 #include
导出.cpp。

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

缺点是,当我们决定使用新的存档类型时,我们需要重建所有内容,但我们发现这比多态存档支持更容易使用。

You can use EXPORT_IN_OBJECT but the file that contains BOOST_CLASS_EXPORT must also include all the archive hpp files that plan to use.

This is because the BOOST_CLASS_EXPORT macro registers the derived type information which each archive it thinks you will use (implicitly determined based upon which archives you have included.)

In your example, use EXPORT_IN_OBJECT but also add #include
to export.cpp.

In our code, we created archives.hpp that contains the archives we use and include it where ever we need to use BOOST_CLASS_EXPORT. (That way we have a single official list of archives.)

The downside is that we need to rebuild everything when we decide to use a new archive type, but we found that much easier to use than the polymorphic archive support.

灰色世界里的红玫瑰 2024-09-19 19:22:08

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

以下是我修复它的方法:

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

    #include ;
    BOOST_CLASS_EXPORT(测试命名空间::派生类)
    

这就是我必须做的全部事情。

This problem drove me insane until I realized that my base class was not polymorphic. In other words, it never used the keyword "virtual" anywhere. Because I didn't need polymorphic behavior.

Here is how I fixed it:

  1. I just slapped the keyword "virtual" on some random method in my base class.
  2. In my derived class's .cpp file, I added the following:

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

This is all that I had to do.

灰色世界里的红玫瑰 2024-09-19 19:22:08

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

you can use and unique BOOST_CLASS_EXPORT_GUID() for each .cpp
and add it only in the .cpp. not the .h

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文