加速序列化,按基本类型加载存档的类会产生错误的数据

时间:2018-07-17 20:25:56

标签: c++ serialization boost

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


在我的示例中,我有两个类:通用BaseClass和专用DerivedClass(类似于我计划使用Boost的方式)。 BaseClass只有一个成员,即名为name的字符串,默认为“ BaseClass”。 DerivedClass公开继承BaseClass,将name设置为其他内容,并拥有自己的唯一成员data

在主程序中,我创建了一个DerivedClass,其中data设置为“特别酷的东西”,并创建了一个BaseClass,其中name是“常规的东西”。我将这两个都用boost::archive::text_oarchive写入文件,然后读回第一个对象DerivedClass两次(两次都创建std::ifstream)。第一次读回去时,我将其放在BaseClass*中。调用BaseClass::printData()(一种打印std::typeidname的虚拟方法)将打印出以下内容:

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

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

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

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

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

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

9BaseClass: DerivedClass

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

我才刚刚开始学习如何使用该库,我在网上发现的大多数类似问题和文档都没有效果(即,尽管使用0BOOST_EXPORT_CLASS很可能是我使用不正确)。


这是我的代码:

main.cpp

BOOST_CLASS_TYPE_INFO

baseclass.h

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

derivedclass.hpp

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

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

1 个答案:

答案 0 :(得分:1)

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

所以,可以说:

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

并反序列化:

Base* b = nullptr;
boost_in >> b;

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

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

导出类型

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

演示

查看 Live On Wandbox

  • 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

    #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

    #include "baseclass.h"
    #include <boost/archive/text_oarchive.hpp>
    #include <boost/archive/text_iarchive.hpp>
    BOOST_CLASS_EXPORT_IMPLEMENT(BaseClass)
    
  • 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

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

输出: