加速序列化,按基本类型加载存档的类会产生错误的数据 [英] Boost serialization, loading an archived class by base type gives wrong data

查看:50
本文介绍了加速序列化,按基本类型加载存档的类会产生错误的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我将其实现到项目中之前,我编写了一个示例程序来弄清楚Boost的序列化库,但是,我有一些无法解释的行为.

I wrote an example program to figure out Boost's serialization library before I implemented it into a project, however, I got some unexplained behavior.

在我的示例中,我有两个类:通用的 BaseClass 和专门的 DerivedClass (类似于我打算使用Boost的方式). BaseClass 只有一个成员,一个名为 name 的字符串,默认为"BaseClass". DerivedClass 公开继承 BaseClass ,将 name 设置为其他名称,并具有自己的唯一成员 data .

In my example, I had two classes: a generic BaseClass and a specialized DerivedClass (analogous to what I plan to use Boost for). BaseClass only has one member, a string called name, which defaults to "BaseClass". DerivedClass publicly inherits BaseClass, sets name to something else and has its own unique member, data.

在主程序中,我创建一个 DerivedClass 并将 data 设置为特殊的东西",并创建一个 BaseClass 并使用名称常规内容".我将这两个都写入 boost :: archive :: text_oarchive 的文件中,然后读回第一个对象 DerivedClass ,两次(重新创建 std::ifstream 两次).第一次读回来,我把它放在了 BaseClass * 上.调用 BaseClass :: printData()(一种打印 std :: typeid name 的虚拟方法)将按照以下内容打印:/p>

In the main program, I create a DerivedClass with data set to "special cool stuff", and a BaseClass with name "regular stuff". I write both of these to a file with boost::archive::text_oarchive, and read the first object, the DerivedClass, back twice (recreating the std::ifstream both times). The first time reading it back, I put it to a BaseClass*. Calling BaseClass::printData() (a virtual method that prints the std::typeid and name) prints something along the lines of:

 --- Storage done, now loading the first object as BaseClass --- 
9BaseClass: 0

接下来,当我将其加载为 DerivedClass * 并调用 DerivedClass :: printData()(从 BaseClass 覆盖以包括成员 data 在输出中)正确打印:

Next, when I load it as a DerivedClass* and call DerivedClass::printData() (which is overridden from BaseClass to include the member data in the output) correctly prints:

 --- Storage done, now loading the first object as DerivedClass --- 
12DerivedClass: DerivedClass AND special cool stuff

在我正在写入的文件中,我看到了:

Looking in the file I'm writing to, I see this:

22 serialization::archive 15 0 1 0
0 1 0
1 12 DerivedClass 18 special cool stuff 1
2 13 regular stuff

当我在原始的,预序列化的 DerivedClass 上调用 BaseClass :: printData()时,我得到了:

And when I call BaseClass::printData() on the original, pre-serializing DerivedClass, I get this:

9BaseClass: DerivedClass

很显然,正确存储了 DerivedClass .关于将其作为 BaseClass 加载以检查 name 的某件事搞砸了.我想不出为什么它会给我一个包含 0 std :: string .

Obviously, the DerivedClass is being stored correctly. Something about loading it as a BaseClass to check name is messing up. I cannot think of why it would give me a std::string containing 0.

我才刚刚开始学习如何使用该库,并且我在网上找到的大多数类似问题和文档都无效(即,使用 BOOST_EXPORT_CLASS BOOST_CLASS_TYPE_INFO ,尽管很可能是我没有正确使用它们.)

I'm just starting to learn how to use this library, and most of the similar questions and documentation I've found online have no effect (ie, using BOOST_EXPORT_CLASS or BOOST_CLASS_TYPE_INFO, although it could very well be I was using them incorrectly).

这是我的代码:

#include <iostream>
#include <fstream>
#include <string>

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/nvp.hpp>

#include "baseclass.h"
#include "derivedclass.h"

int main() {
    BaseClass*  testBase = new BaseClass("regular stuff");
    DerivedClass* testDerivate = new DerivedClass("special cool stuff");

    testDerivate->BaseClass::printData();

    std::cout << std::endl << " --- " << "Storing objects in the file 'output'..." << " --- " << std::endl;

    std::ofstream output("storage");

    {
        boost::archive::text_oarchive boost_out(output);
        boost_out << (testDerivate);
        testDerivate->printData();
        boost_out << (testBase);
        testBase->printData();
    }

    std::cout << std::endl << " --- " << "Storage done, now loading the first object as BaseClass" << " --- " << std::endl;

    {
        std::ifstream input("storage");
        BaseClass*  base;
        boost::archive::text_iarchive boost_in(input);
        boost_in >> (base);
        base->printData();
        input.close();
    }

    std::cout << std::endl << " --- " << "Storage done, now loading the first object as DerivedClass" << " --- " << std::endl;

    {
        std::ifstream input("storage");
        DerivedClass* derive;
        boost::archive::text_iarchive boost_in(input);
        boost_in >> (derive);
        derive->printData();
        input.close();
    }

    return 0;
}

baseclass.h

#pragma once

#include <string>
#include <iostream>
#include <typeinfo>

#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>

class BaseClass
{
public:
    BaseClass() {
        name = "BaseClass";
    }

    BaseClass(std::string custom) {
        name = custom;
    }

    virtual ~BaseClass() {}

    virtual void printData() {
        std::cout << typeid(*this).name() << ": " << name << std::endl;   
    }

protected:
    std::string name;

private:    
    friend class boost::serialization::access;

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

derivedclass.hpp

#pragma once

#include <string>
#include <iostream>
#include <typeinfo>

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

#include "baseclass.h"

class DerivedClass :  public BaseClass
{
public:
    DerivedClass() : BaseClass("DerivedClass") {}
    DerivedClass(std::string custom) : BaseClass("DerivedClass") {
        data = custom;
    }

    virtual ~DerivedClass() {}

    void printData() override {
        std::cout << typeid(*this).name() << ": " << name << " AND " << data << std::endl;
    }

protected:
    std::string data;

private:
    friend class boost::serialization::access;

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


很抱歉,如果这有点长,我想尽可能地描述一下.我对使用Boost还是很陌生,对C ++的使用还不是很了解,所以即使您对我的代码有一些一般性的评论,也还是很感激的.


Sorry if this is a bit long, I wanted to be as descriptive as possible. I'm very new to using Boost and I'm not all that experienced with C++, so even if you just have some general comments on my code, I'd appreciate it.

推荐答案

您没有加载与序列化相同的 types .

You're not loading the same types as you're serializing.

因此,虽然可以说:

Base* b = new Derived();
boost_out << b;

并反序列化:

Base* b = nullptr;
boost_in >> b;

无法序列化 Derived * ,并将其反序列化为 Base * ,反之亦然.

You cannot serialize a Derived* and deserialize it as Base* or vice versa.

因此,如果您知道接收代码必须支持所有派生类,请使其明确并序列化 Base * .

So, if you know the receiving code must support all derived classes, make it explicit and serialize a Base*.

要让反序列化端知道在反序列化多态基址指针时可能遇到的一组派生类型集,请导出这些类型.

To let the de-serializing end know what the possible set of derived types is that could be encountered in deserializing a polymorphic base pointer, export the types.

在"a.hpp"标头中包含 BOOST_CLASS_EXPORT 本身与其他序列化特征一样,将导致很难或不可能遵循上述有关在 BOOST_CLASS_EXPORT之前包含存档标头的规则被调用.最好使用标题声明中的 BOOST_CLASS_EXPORT_KEY 和类定义文件中的 BOOST_CLASS_EXPORT_IMPLEMENT 解决此问题.

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.

[...片段...]

[ ... snip ... ]

BOOST_CLASS_EXPORT 放置在库代码中将无效,除非还包括存档类标头.因此,在构建库时,应包括他预期使用的所有存档类的所有标头.或者,可以仅包含Polymoprhic [sic] 档案的标头.

Placing BOOST_CLASS_EXPORT in library code will have no effect unless archive class headers are also included. So when building a library, one should include all headers for all the archive classes which he anticipates using. Alternatively, one can include headers for just the Polymoprhic [sic] Archives.

查看 在魔盒上直播

  • main.cpp

  • main.cpp

#include <iostream>
#include <fstream>
#include <string>

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/nvp.hpp>
//#include <boost/serialization/export.hpp>

#include "baseclass.h"
#include "derivedclass.h"

int main() {
    BaseClass* testBase = new BaseClass("regular stuff");
    BaseClass* testDerived = new DerivedClass("special cool stuff");

    std::cout << std::endl << " --- " << "Storing objects in the file 'output'..." << " --- " << std::endl;

    {
        std::ofstream output("storage");
        boost::archive::text_oarchive boost_out(output);
        boost_out << testBase << testDerived;
    }

    std::cout << std::endl << " --- " << "Storage done, now loading the first object as BaseClass" << " --- " << std::endl;

    {
        std::ifstream input("storage");
        BaseClass* b1;
        BaseClass* b2;
        boost::archive::text_iarchive boost_in(input);
        boost_in >> b1 >> b2;

        std::cout << "b1: "; b1->printData();
        std::cout << "b2: "; b2->printData();
    }
}

  • baseclass.h

  • baseclass.h

    #pragma once
    
    #include <string>
    #include <iostream>
    #include <typeinfo>
    
    #include <boost/serialization/access.hpp>
    #include <boost/serialization/nvp.hpp>
    #include <boost/serialization/export.hpp>
    
    class BaseClass
    {
    public:
        BaseClass() {
            name = "BaseClass";
        }
    
        BaseClass(std::string custom) {
            name = custom;
        }
    
        virtual ~BaseClass() {}
    
        virtual void printData() {
            std::cout << typeid(*this).name() << ": " << name << std::endl;   
        }
    
    protected:
        std::string name;
    
    private:    
        friend class boost::serialization::access;
    
        template<class Archive>
        void serialize(Archive & ar, unsigned) {
            ar & (name);
        }
    };
    
    BOOST_CLASS_EXPORT_KEY2(BaseClass, "BaseClass");
    

  • baseclass.cpp

  • baseclass.cpp

    #include "baseclass.h"
    #include <boost/archive/text_oarchive.hpp>
    #include <boost/archive/text_iarchive.hpp>
    BOOST_CLASS_EXPORT_IMPLEMENT(BaseClass)
    

  • derivedclass.h

  • derivedclass.h

    #pragma once
    
    #include <string>
    #include <iostream>
    #include <typeinfo>
    
    #include <boost/serialization/base_object.hpp>
    #include <boost/serialization/access.hpp>
    #include <boost/serialization/export.hpp>
    
    #include "baseclass.h"
    
    class DerivedClass :  public BaseClass
    {
    public:
        DerivedClass() : BaseClass("DerivedClass") {}
        DerivedClass(std::string custom) : BaseClass("DerivedClass") {
            data = custom;
        }
    
        virtual ~DerivedClass() {}
    
        void printData() override {
            std::cout << typeid(*this).name() << ": " << name << " AND " << data << std::endl;
        }
    
    protected:
        std::string data;
    
    private:
        friend class boost::serialization::access;
    
        template<class Archive>
        void serialize(Archive & ar, unsigned) {
            ar & (boost::serialization::base_object<BaseClass>(*this));
            ar & (data);
        }
    };
    
    BOOST_CLASS_EXPORT_KEY2(DerivedClass, "DerivedClass");
    

  • derivedclass.cpp

  • derivedclass.cpp

    #include "derivedclass.h"
    #include <boost/archive/text_oarchive.hpp>
    #include <boost/archive/text_iarchive.hpp>
    BOOST_CLASS_EXPORT_IMPLEMENT(DerivedClass)
    

  • 输出:

    这篇关于加速序列化,按基本类型加载存档的类会产生错误的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆