C++ Boost(C+;+;)中没有类跟踪的派生类序列化

C++ Boost(C+;+;)中没有类跟踪的派生类序列化,c++,serialization,boost,boost-serialization,C++,Serialization,Boost,Boost Serialization,当通过基类指针序列化派生类时,我在boost序列化方面遇到一些问题。我需要一个在系统中接收某些对象时对其进行序列化的系统,因此我需要随时间进行序列化。这不是一个真正的问题,因为我可以打开一个boost::archive::binary\u oarchive并在需要时序列化对象。我很快注意到boost正在按内存地址执行对象跟踪,因此第一个问题是,共享同一内存地址的不同对象在时间上被保存为同一对象。在所需的派生类中使用以下宏可以解决此问题: BOOST\u CLASS\u跟踪(className,B

当通过基类指针序列化派生类时,我在boost序列化方面遇到一些问题。我需要一个在系统中接收某些对象时对其进行序列化的系统,因此我需要随时间进行序列化。这不是一个真正的问题,因为我可以打开一个
boost::archive::binary\u oarchive
并在需要时序列化对象。我很快注意到boost正在按内存地址执行对象跟踪,因此第一个问题是,共享同一内存地址的不同对象在时间上被保存为同一对象。在所需的派生类中使用以下宏可以解决此问题:

BOOST\u CLASS\u跟踪(className,BOOST::serialization::track\u never)

这很好,但同样,当基类不是抽象类时,基类没有正确序列化。在下面的示例中,基类序列化方法仅对第一个对象调用一次。在下面的例子中,boost假设该对象之前已经序列化过,尽管该对象的类型不同

#include <iostream>
#include <fstream>
#include <boost/serialization/export.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/archive/archive_exception.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

using namespace std;

class AClass{
public:
    AClass(){}
    virtual ~AClass(){}
private:
    double a;
    double b;
    //virtual void virtualMethod() = 0;
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & a;
        ar & b;
        cout << "A" << endl;
    }
};
//BOOST_SERIALIZATION_ASSUME_ABSTRACT(Aclass)
//BOOST_CLASS_TRACKING(AClass, boost::serialization::track_never)

class BClass : public AClass{
public:
    BClass(){}
    virtual ~BClass(){}
private:
    double c;
    double d;
    virtual void virtualMethod(){};
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & boost::serialization::base_object<AClass>(*this);
        ar & c;
        ar & d;
        cout << "B" << endl;
    }
};
// define export to be able to serialize through base class pointer
BOOST_CLASS_EXPORT(BClass)
BOOST_CLASS_TRACKING(BClass, boost::serialization::track_never)


class CClass : public AClass{
public:
    CClass(){}
    virtual ~CClass(){}
private:
    double c;
    double d;
    virtual void virtualMethod(){};
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & boost::serialization::base_object<AClass>(*this);
        ar & c;
        ar & d;
        cout << "C" << endl;
    }
};
// define export to be able to serialize through base class pointer
BOOST_CLASS_EXPORT(CClass)
BOOST_CLASS_TRACKING(CClass, boost::serialization::track_never)

int main() {
    cout << "Serializing...." << endl;
    {
        ofstream ofs("serialization.dat");
        boost::archive::binary_oarchive oa(ofs);
        for(int i=0;i<5;i++)
        {
            AClass* baseClassPointer = new BClass();
            // serialize object through base pointer
            oa << baseClassPointer;
            // free the pointer so next allocation can reuse memory address
            delete baseClassPointer;
        }

        for(int i=0;i<5;i++)
        {
            AClass* baseClassPointer = new CClass();
            // serialize object through base pointer
            oa << baseClassPointer;
            // free the pointer so next allocation can reuse memory address
            delete baseClassPointer;
        }
    }
    getchar();
    cout << "Deserializing..." << endl;
    {
        ifstream ifs("serialization.dat");
        boost::archive::binary_iarchive ia(ifs);
        try{
            while(true){
                AClass* a;
                ia >> a;
                delete a;
            }
        }catch(boost::archive::archive_exception const& e)
        {

        }
    }
    return 0;
}
因此基类只被序列化一次,尽管派生类显式地具有track\u never标志。有两种不同的解决方法来修复此行为。第一种方法是使用纯虚拟方法使基类抽象,并调用宏
BOOST\u SERIALIZATION\u aspect\u abstract(Aclass)
,第二种方法是将track\u never标志也放在基类中(在代码中注释)

这些解决方案都不符合我的要求,因为我希望在将来对系统状态进行准时序列化,这将需要跟踪扩展a(而不是B或C)的给定数据类的功能,而且AClass不应该是抽象的


有什么提示吗?是否有任何方法可以显式调用基类序列化方法,以避免基类中的跟踪功能(已在派生类中禁用)?

最终问题似乎是,
boost::serialization
存档表示单个时间点的状态,您希望归档文件包含已更改的状态,即已重用的指针。我认为没有一个简单的
boost::serialization
标志可以诱导您想要的行为

不过,我认为还有其他解决办法可能就足够了。您可以将类的序列化封装到它自己的归档中,然后归档封装。也就是说,您可以像这样实现
B
的序列化(注意,您必须将
serialize()
拆分为
save()
load()
):

这种技术的一个潜在缺点是封装的存储开销。原始测试程序的结果为319字节,而修改后的测试程序产生664字节。但是,如果将gzip应用于两个输出文件,则原始文件的大小为113字节,修改文件的大小为116字节。如果空间是一个问题,那么我建议向外部序列化添加压缩,这可以通过
boost::iostreams
轻松完成


另一种可能的解决方法是将实例的生命周期延长到存档的生命周期,这样指针就不会被重用。您可以通过将
共享的\u ptr
实例的容器关联到您的归档文件,或者通过从内存池分配实例来实现这一点。

仔细查看boost::serialization之后,我还确信对于您的请求,没有简单的解决方案。 正如您已经提到的,序列化的跟踪行为是在带有BOOST_class_跟踪的逐类基类上声明的。 这个常量全局信息在oserializer类的虚拟方法跟踪中被解释

   virtual bool tracking(const unsigned int /* flags */)
因为这是一个模板类,所以可以显式地为类实例化此方法

namespace boost {
namespace archive {
namespace detail {

template<>
    virtual bool oserializer<class binary_oarchive, class AClass >::tracking(const unsigned int f /* flags */) const {
        return do_your_own_tracking_decision();
    }

}}}
存档标志在basic_archive.hpp中声明

enum archive_flags {
    no_header = 1,  // suppress archive header info
    no_codecvt = 2,  // suppress alteration of codecvt facet
    no_xml_tag_checking = 4,   // suppress checking of xml tags
    no_tracking = 8,           // suppress ALL tracking
    flags_last = 8
};
目前似乎不支持no_跟踪,但现在可以将此行为添加到跟踪中

template<>
    virtual bool oserializer<class binary_oarchive, class AClass >::tracking(const unsigned int f /* flags */) const {
        return !(f & no_tracking);
    } 
这就是你们例子中的变化

int main() {
    cout << "Serializing...." << endl;
    {
        ofstream ofs("serialization1.dat");
        boost::archive::binary_oarchive oa_nt(ofs, boost::archive::archive_flags::no_tracking);
        //boost::archive::binary_oarchive oa(ofs);
        for(int i=0;i<5;i++)
        {
            AClass* baseClassPointer = new BClass();
            // serialize object through base pointer
            oa_nt << baseClassPointer;
            // free the pointer so next allocation can reuse memory address
            delete baseClassPointer;
        }

        ofstream ofs2("serialization2.dat");
        boost::archive::binary_oarchive oa(ofs2);
        //boost::archive::binary_oarchive oa(ofs);

        for(int i=0;i<5;i++)
        {
            AClass* baseClassPointer = new CClass();
            // serialize object through base pointer
            oa << baseClassPointer;
            // free the pointer so next allocation can reuse memory address
            delete baseClassPointer;
        }
    }
    getchar();
    cout << "Deserializing..." << endl;
    {
        ifstream ifs("serialization1.dat");
        boost::archive::binary_iarchive ia(ifs);
        try{
            while(true){
                AClass* a;
                ia >> a;
                delete a;
            }
        }catch(boost::archive::archive_exception const& e)
        {

        }

        ifstream ifs2("serialization2.dat");
        boost::archive::binary_iarchive ia2(ifs2);
        try{
            while(true){
                AClass* a;
                ia2 >> a;
                delete a;
            }
        }catch(boost::archive::archive_exception const& e)
        {

        }

    }
    return 0;
}


namespace boost {
namespace archive {
namespace detail {

template<>
    virtual bool oserializer<class binary_oarchive, class AClass >::tracking(const unsigned int f /* flags */) const {
        return !(f & no_tracking);
    }

}}}
intmain(){

cout可以让boost假设A是虚拟的,即使它不是(我的意思是,只需取消注释行
boost\u SERIALIZATION\u assume\u ABSTRACT(Aclass)
,然后尝试编译)?添加了关于封装存档的存储开销的说明。谢谢…但此解决方案使序列化过程复杂化,并增加了其大小。我也不能延长指针的寿命,因为系统打算无限期地工作。无论如何,感谢您的帮助!似乎是一个好方法!我认为它可以满足我的要求记住。让我明天更详细地检查和测试您的响应。我会告诉您的。谢谢!最后我花了一些时间测试您的方法,但它似乎不起作用。它在虚拟跟踪方法中出现错误,因为它不在oserializer类范围内。“虚拟类外声明”。并且我无法修改boost库:(最终使其工作!我可以打开带有标志的文件并选择何时进行跟踪或不进行跟踪!谢谢!我编辑了您的代码以便能够编译。这种方法似乎满足了我的要求!
binary_oarchive(std::ostream & os, unsigned int flags = 0) 
enum archive_flags {
    no_header = 1,  // suppress archive header info
    no_codecvt = 2,  // suppress alteration of codecvt facet
    no_xml_tag_checking = 4,   // suppress checking of xml tags
    no_tracking = 8,           // suppress ALL tracking
    flags_last = 8
};
template<>
    virtual bool oserializer<class binary_oarchive, class AClass >::tracking(const unsigned int f /* flags */) const {
        return !(f & no_tracking);
    } 
 boost::archive::binary_oarchive oa_nt(ofs, boost::archive::archive_flags::no_tracking);
int main() {
    cout << "Serializing...." << endl;
    {
        ofstream ofs("serialization1.dat");
        boost::archive::binary_oarchive oa_nt(ofs, boost::archive::archive_flags::no_tracking);
        //boost::archive::binary_oarchive oa(ofs);
        for(int i=0;i<5;i++)
        {
            AClass* baseClassPointer = new BClass();
            // serialize object through base pointer
            oa_nt << baseClassPointer;
            // free the pointer so next allocation can reuse memory address
            delete baseClassPointer;
        }

        ofstream ofs2("serialization2.dat");
        boost::archive::binary_oarchive oa(ofs2);
        //boost::archive::binary_oarchive oa(ofs);

        for(int i=0;i<5;i++)
        {
            AClass* baseClassPointer = new CClass();
            // serialize object through base pointer
            oa << baseClassPointer;
            // free the pointer so next allocation can reuse memory address
            delete baseClassPointer;
        }
    }
    getchar();
    cout << "Deserializing..." << endl;
    {
        ifstream ifs("serialization1.dat");
        boost::archive::binary_iarchive ia(ifs);
        try{
            while(true){
                AClass* a;
                ia >> a;
                delete a;
            }
        }catch(boost::archive::archive_exception const& e)
        {

        }

        ifstream ifs2("serialization2.dat");
        boost::archive::binary_iarchive ia2(ifs2);
        try{
            while(true){
                AClass* a;
                ia2 >> a;
                delete a;
            }
        }catch(boost::archive::archive_exception const& e)
        {

        }

    }
    return 0;
}


namespace boost {
namespace archive {
namespace detail {

template<>
    virtual bool oserializer<class binary_oarchive, class AClass >::tracking(const unsigned int f /* flags */) const {
        return !(f & no_tracking);
    }

}}}