【问题标题】:How to serialize object with shared_ptr member using boost如何使用 boost 使用 shared_ptr 成员序列化对象
【发布时间】:2015-01-22 11:19:46
【问题描述】:

有抽象的I1和派生的C1

有抽象的I2和派生的C2

I1 拥有shared_ptr<I2>。如何使用 boost serializaton 使它们可序列化?我正在尝试这样做,但我的应用程序出现异常。

#include <sstream>
#include <boost/shared_ptr.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>

struct I1
{
    I1() {}
    virtual ~I1() = 0 {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
    }
};

struct C1 : I1
{
    virtual ~C1() {}

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

struct I2
{
    virtual ~I2() = 0 {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar & p;
    }

    boost::shared_ptr<I1> p;
};

struct C2 : I2
{
    C2() { p = boost::shared_ptr<I1>(new C1); }
    virtual ~C2() { }

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

int main()
{
    C2 c2;

    std::string s;
    std::stringstream ss(s);

    boost::archive::binary_oarchive oa(ss);
    oa.register_type<I1>();
    oa.register_type<C1>();
    oa.register_type<I2>();
    oa.register_type<C2>();

    oa << c2;

    boost::archive::binary_iarchive ia(ss);
    //ia.register_type<I1>(); // cannot instantiate abstract class
    ia.register_type<C1>();
    //ia.register_type<I2>(); // cannot instantiate abstract class
    ia.register_type<C2>();

    ia >> c2;
}

【问题讨论】:

  • 你能告诉我们哪个编译器接受=0 {} 语法吗?我知道它存在,但我不知道接受此输入的编译器
  • 有趣的是,您的代码在 Linux 上的 gcc 4.8.1 上运行良好(好吧,除了 =0 {} 语法)。
  • 你能试试用 msvc 运行这段代码吗?
  • @Ufx,我就是这么做的。您可以在我的答案中准确看到我使用的内容和输出。

标签: c++ serialization boost deserialization


【解决方案1】:

添加

BOOST_SERIALIZATION_ASSUME_ABSTRACT(I1)
BOOST_SERIALIZATION_ASSUME_ABSTRACT(I2)

根据文档http://www.boost.org/doc/libs/1_39_0/libs/serialization/doc/traits.html#abstract

更新

我刚刚使用 VS2013RTM 和 Boost 1_55 进行了验证,它是 JustWorks(TM),我已经

  • 删除了抽象基的类型注册(它们永远不能具体从存档中加载)
  • 添加

    #pragma warning(disable: 4244)
    #include <boost/config/warning_disable.hpp>
    

    在文件的顶部以消除已知的喋喋不休的警告

代码编译并运行没有错误。为了好的风格,你可能应该

这是我最终得到的完整代码:

#pragma warning(disable: 4244)
#include <boost/config/warning_disable.hpp>
#include <sstream>
#include <boost/shared_ptr.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>

struct I1
{
    I1() {}
    virtual ~I1() = 0 {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
    }
};

struct C1 : I1
{
    virtual ~C1() {}

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

struct I2
{
    virtual ~I2() = 0 {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar & p;
    }

    boost::shared_ptr<I1> p;
};

struct C2 : I2
{
    C2() { p = boost::shared_ptr<I1>(new C1); }
    virtual ~C2() { }

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

int main()
{
    boost::shared_ptr<I2> c2(new C2);

    std::string s;
    std::stringstream ss(s);

    boost::archive::text_oarchive oa(ss);
    oa.register_type<C1>();
    oa.register_type<C2>();

    oa << c2;
    std::cout << "Serialized form: '" << ss.str() << "'\n";

    boost::archive::text_iarchive ia(ss);
    ia.register_type<C1>();
    ia.register_type<C2>();

    ia >> c2;
}

这是输出:

【讨论】:

  • 哪里需要添加?
  • 我只是在接口类的声明之后立即添加它们
  • @Ufx 对于它的价值,我现在已经在 VS2013 上对其进行了测试——我之前无法访问 Windows。也许您应该在一个独立的、全新的控制台应用程序中尝试它,以排除项目/构建设置的其余部分有问题。
  • 我刚刚替换了除主要功能(和标题)之外的所有功能,但它仍然崩溃。 martin_pr 的解决方案不会崩溃。
【解决方案2】:

boost 序列化文档说 here 关于 BOOST_CLASS_EXPORT 的有趣事情:

... BOOST_CLASS_EXPORT ...

因此,导出的需要隐含在派生类的使用中,派生类通过指针或对其基类的引用进行操作。

您的p 指针正是这样做的。将这些宏添加到您的代码中还可以摆脱来自主程序的丑陋显式 register_type() 调用,这也很好:)

所以,这段代码似乎可以在 VS2014 中编译和工作:

#include <sstream>
#include <boost/shared_ptr.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/export.hpp>

struct I1
{
    I1() {}
    virtual ~I1() = 0 {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
    }
};

BOOST_CLASS_EXPORT(I1)

struct C1 : I1
{
    virtual ~C1() {}

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

BOOST_CLASS_EXPORT(C1)

struct I2
{
    virtual ~I2() = 0 {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar & p;
    }

    boost::shared_ptr<I1> p;
};

BOOST_CLASS_EXPORT(I2)

struct C2 : I2
{
    C2() { p = boost::shared_ptr<I1>(new C1); }
    virtual ~C2() { }

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

BOOST_CLASS_EXPORT(C2)

int main()
{
    C2 c2;

    std::string s;
    std::stringstream ss(s);

    boost::archive::binary_oarchive oa(ss);
    oa << c2;

    boost::archive::binary_iarchive ia(ss);
    ia >> c2;
}

有趣的是,Boost 文档中的声明显然不适用于所有编译器,并且互联网上的许多代码示例在 VS2014 中都不起作用。

【讨论】:

  • 我实际上在虚拟机中安装了 VS2014 来尝试这个,因为以这种方式序列化共享指针必须工作:)
【解决方案3】:

我认为您也不应该在输出存档中注册纯虚拟类。

或者,您可以使用export。定义类后,将其余代码替换为:

#include <boost/serialization/export.hpp>
BOOST_CLASS_EXPORT(C1)
BOOST_CLASS_EXPORT(C2)

int main()
{
    C2 c2;

    std::string s;
    std::stringstream ss(s);

    {
       boost::archive::binary_oarchive oa(ss);
       oa << c2;
    }

    boost::archive::binary_iarchive ia(ss);
    ia >> c2;
}

我将输出存档放入一个单独的块中。我认为它很可能在没有它的情况下工作,但我想确保一切都被刷新(通过超出范围)。

【讨论】:

  • 对我没有帮助。对你起作用吗?我使用 MSVC12。
  • 它在 clang 和 gcc 上对我有用。您是否尝试了这两种方法(删除抽象类的 register_type ,用上面的代码替换 main )?还有什么错误,同一个?
  • 我认为错误是同一个。 archive_exception(archive_exception::unregistered_class) “未注册的类”。调用栈:pastebin.com/wU7ARa4F
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-11
  • 1970-01-01
  • 2014-07-01
  • 2021-02-02
  • 2013-07-15
相关资源
最近更新 更多