【问题标题】:Problems deserializing a pointer to a derived class using Boost:serialize使用 Boost:serialize 反序列化指向派生类的指针的问题
【发布时间】:2012-01-11 12:45:47
【问题描述】:

我在尝试使用 boost 序列化反序列化指向派生类的指针时遇到了一个奇怪的问题。我有一个基础,并在它们之外使用保存/加载功能(非侵入式版本)派生,但每次我尝试反序列化指针时,我都会得到“输入流错误”异常或“未注册类”异常。这是我的工作:

首先我定义我的类:

#include <fstream>
#include <iomanip>

#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/archive_exception.hpp>
#include "boost/serialization/split_free.hpp"
#include "boost/serialization/export.hpp"
#include "boost/serialization/utility.hpp"
#include <boost/serialization/string.hpp>
#include <boost/serialization/binary_object.hpp>

class Base
{
public:
    bool isEnabled;
    Base();
    virtual ~Base(){}
};
Base::Base()
{
    isEnabled = 0;
}

class Derived : public Base
{

public:
    Derived();
    virtual ~Derived(){}
    int layerHeight;
};
Derived::Derived():Base()
{}

然后我确保他们的特征是我需要的:

BOOST_CLASS_EXPORT_GUID(Base, "Base")
BOOST_SERIALIZATION_SPLIT_FREE(Base)
BOOST_CLASS_IS_WRAPPER(Base)
BOOST_CLASS_TRACKING(Base, boost::serialization::track_selectively)
BOOST_CLASS_IMPLEMENTATION(Base, boost::serialization::object_class_info)

BOOST_SERIALIZATION_SPLIT_FREE(Derived)
BOOST_CLASS_EXPORT_GUID(Derived, "Derived")
BOOST_CLASS_IS_WRAPPER(Derived)
BOOST_CLASS_IMPLEMENTATION(Derived, boost::serialization::object_class_info)
BOOST_CLASS_TRACKING(Derived, boost::serialization::track_selectively)

接下来我定义实际的保存/加载函数:

namespace boost {

    namespace serialization {

    template<class Archive>
    void save(Archive & ar,const Base& obj, const unsigned int version)
    {
        bool isEnabled = obj.isEnabled;
        ar << BOOST_SERIALIZATION_NVP(isEnabled);
    }
    template<class Archive>
    void load(Archive & ar, Base& obj, const unsigned int version)
    {
        bool isEnabled;
        ar >> BOOST_SERIALIZATION_NVP(isEnabled);
    }
    } // namespace serialization
} // namespace boost

namespace boost {
template<>
struct is_virtual_base_of<Base, Derived>: public mpl::true_ {};

namespace serialization {

template<class Archive>
void save(Archive & ar,const Derived& obj, const unsigned int version)
{
    ar & boost::serialization::base_object<Base>(obj);
    int height =obj.layerHeight;
    ar << BOOST_SERIALIZATION_NVP(height);
}
template<class Archive>
void load(Archive & ar, Derived& obj, const unsigned int version)
{
    ar.template register_type<Base>();
    ar.template register_type<Derived>();
    ar & boost::serialization::base_object<Base>(obj);
    int height;
    ar >> BOOST_SERIALIZATION_NVP(height);
}
} // namespace serialization
} // namespace boost

还有 2 个我从 Docs 借来的保存/加载助手

template <typename T>
void save_schedule(const T& s, const char * filename){
    // make an archive
    std::ofstream ofs(filename);
    assert(ofs.good());
    boost::archive::xml_oarchive oa(ofs);
    oa << BOOST_SERIALIZATION_NVP(s);
}

template <typename T>
void restore_schedule(T &s, const char * filename)
{
    // open the archive
    std::ifstream ifs(filename);
    assert(ifs.good());
    boost::archive::xml_iarchive ia(ifs);
    // restore the schedule from the archive
    ia >> BOOST_SERIALIZATION_NVP(s);
}

最后 - 这是我尝试全部使用它的方法

int main(int argc, char *argv[])
{
    Base* basePointer = new Base();
    Base* objectPointer = new Derived();
    Derived * secondObjectPointer = new Derived();
    Derived justObject;

    save_schedule(basePointer, "C:\\basePointer.xml");
    save_schedule(objectPointer, "C:\\objectPointer.xml");
    save_schedule(secondObjectPointer , "C:\\secondObjectPointer.xml");
    save_schedule(justObject, "C:\\justObject.xml");

    //this works OK
    restore_schedule(basePointer, "C:\\basePointer.xml");

    //this gives "Input Stream Error"
    restore_schedule(objectPointer, "C:\\objectPointer.xml");

    //this gives "Unregistered class"
    restore_schedule(secondObjectPointer, "C:\\secondObjectPointer.xml");

    //This works >__< But I need to serialize pointers so I cannot use this
    restore_schedule(justObject, "C:\\justObject.xml");
}

我做错了什么?为什么我不能反序列化除了指向基类的指针之外的任何东西?

【问题讨论】:

  • 如果您解决了问题,请将解决方案发布为答案。
  • 为此,我需要找到如何做到这一点:) 对不起,我是全新的。附:在接下来的 4 小时内,我似乎无法将其作为答案发布 - 站点限制
  • 那毕竟不是解决方案?你说问题解决了。
  • 这是解决方案,我只是不知道如何发布任何内容作为答案而不是编辑我的帖子,现在事实证明这有 8 小时的限制。
  • 哦,抱歉,我误解了您最初的评论。您的意思是您不知道如何在 SO 上发布答案;我以为你在谈论实施你的解决方案。是的,您必须等待 8 小时才能发布自我回答;不过,请这样做。我已将您的解决方案从问题中删除,因为它不属于那里。谢谢!

标签: c++ serialization boost


【解决方案1】:

UPD:: 经过更多搜索后,我能够将我的问题追溯到这个答案:

boost serialization exception: unregistered class, serializing polymorphic base problem

替换

//original taken from Boost Docs
ar & boost::serialization::base_object<Base>(obj); 

与

// taken from the link above (macro expanded)
ar & boost::serialization::make_nvp( BOOST_PP_STRINGIZE(obj),boost::serialization::base_object<Base >(obj));

确实解决了问题。

附带说明 - 我发现了另一种可能出现并导致“流输入错误”的奇怪错误。它的工作原理是这样的:

如果您的层次结构中甚至有一个构造函数可以初始化一个变量(任何变量)但没有 - 您将在尝试反序列化时遇到流输入错误。

如果类中没有变量 - 一切正常。但如果甚至有一个 - 您必须在该类的构造函数中初始化至少一个变量!我不知道为什么这很重要,但这为我解决了一个主要问题。

【讨论】:

  • 实际上,我很想听听一个解释,当我没有在基类的构造函数中初始化任何东西时会发生什么。我的意思是 - 我仍然用 :Base() 显式调用它......它是否得到优化或任何东西,因为它没有任何东西可以执行?
  • Boost 很强大,但是.. 嗯。我花了过去 2 个小时尝试序列化派生类。阅读教程/书没有什么好处。你的帖子解决了我的编译错误。仍然不知道为什么连官方教程都无法展示这个库的正确用法
  • 实际上,这个问题(没有有用的例子/忘记提及重要的事情)是一个反复出现的问题。每次我尝试使用 boost 中的新东西时,我都会接近这一点 >_
  • 你找到真正的原因了吗,为什么boost需要你初始化一个字段?
  • 不。并不是说我有时间认真研究。 freenode #boost 的 Ppl 猜测这并非不可能,并且可能与 boost 在幕后所做的一些模板有关。当时 - 我很高兴它起作用了...... :)
【解决方案2】:

我不是 Boost 序列化专家。我只体验了两天。我遇到了和你一样的问题,在阅读了完整的文档后,我仍然没有成功解决问题。但是你的解决方案对我有用,让我想到了以下几点。

正如文档在Special Considerations/XML Archives一章中解释的那样:

XML 与其他格式的不同之处在于它需要为 每个数据成员。我们的目标是将这些信息添加到类中 序列化规范,同时仍然允许 用于任何存档的序列化代码。这是通过 要求将所有序列化为 XML 归档的数据序列化为 名称-值对。

这意味着在使用 XML 存档时,每个字段都必须使用名称保存。这就是为什么我们总是需要使用BOOST_SERIALIZATION_NVP 宏,它在 XML 文件中添加参数名称的字符串化转换。

您的解决方案让我认为即使对于基类的序列化,XML 也需要一个与之关联的名称。 boost::serialization::base_object&lt;Base&gt; 不能像 BOOST_SERIALIZATION_NVP 那样提供自动名称,所以我们需要明确地为它提供函数:

template<class T> const nvp< T > boost::serialization::make_nvp(const char * name, T & t)

BOOST_PP_STRINGIZE(obj) 将参数obj 字符串化。就我而言,我更喜欢给出一个字符串字面量:

ar & boost::serialization::make_nvp("MyBase", boost::serialization::base_object<Base>(obj));

这是我的理解。如果我是假的,请纠正我。

【讨论】:

    猜你喜欢
    • 2019-11-20
    • 1970-01-01
    • 1970-01-01
    • 2016-02-19
    • 1970-01-01
    • 1970-01-01
    • 2020-02-11
    • 2015-01-13
    • 1970-01-01
    相关资源
    最近更新 更多