从 boost 序列化档案中构造对象

Posted

技术标签:

【中文标题】从 boost 序列化档案中构造对象【英文标题】:Construct object from boost serialization archive 【发布时间】:2012-03-06 18:26:31 【问题描述】:

是否可以直接从存档中构造对象?

这样的……

// Non-working pseudo code
struct Foo 
    BOOST_SERIALIZATION_SPLIT_MEMBER();
    std::vector<int> data;

    Foo() 
        // populate "data" by doing calculation
        data.push_back(1); data.push_back(2);
    

    template<class Archive>
    Foo( Archive & ar ) 
        // populate "data" by rading the archive
    

    template<class Archive>
    void save(Archive & ar, const unsigned int version) const 
        // Normal serialization of data
        ar << data;
    
;

int main(int argc, const char *argv[])

    // deserialize
    boost::archive::text_iarchive oar(std::cin);
    Foo foo(oar);

    return 0;

【问题讨论】:

是的,为什么不呢?只需添加“ar >> data;”在构造函数中,你就完成了。 (真正的挑战是“数据”是否为常量) @alfC 如果 'data' 没有默认构造函数,你会怎么做? @DavidDoria,正如 Alexander Stepanov 所说,“如果你不让你的类默认可构造,那么你就会得到你应得的”。所有类都应该有一个默认构造函数,如果没有(并且您无法控制它),您必须在Foo( Archive &amp; ar ) : data(something) 级别解决此问题,或者具有Foot(Archive &amp; ar) : data(somefunction(ar)) 的间接级别(但有些东西在第一名)。 @alfC 默认构造函数有什么好处?它只会增加您的对象可能处于的状态数量(其中大部分是您必须注意的不良/无效状态),不是吗? @DavidDoria,您将默认构造函数与未初始化的变量混淆了。默认构造函数应该让您的对象处于有效状态(如果可能的话,也是可预测的状态)。 【参考方案1】:

您可以使用反序列化构造函数

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

#include <fstream>

class Point

public:
    Point() = default;
    Point(boost::archive::text_iarchive& archive)
    
        archive >> *this;
    

    float x = 1.;
    float y = 2.;

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

    template<class TArchive>
    void serialize(TArchive & archive, const unsigned int version)
    
        archive & x;
        archive & y;
    
;


int main()

    Point p;
    p.x = 5;
    p.y = 6;

    std::ofstream outputStream("test.archive");
    boost::archive::text_oarchive outputArchive(outputStream);
    outputArchive << p;
    outputStream.close();

    std::ifstream inputStream("test.archive");
    boost::archive::text_iarchive inputArchive(inputStream);

    Point pointRead(inputArchive);

    std::cout << pointRead.x << " " << pointRead.y << std::endl;

    return 0;

【讨论】:

【参考方案2】:

正如我在评论中所说。 是的,从档案中构建没有问题。 (另一种选择是使用static load 函数,但这可能会导致性能下降)。

我看到你的方法的唯一潜在问题是你的构造函数几乎可以接受任何东西作为参数,这可能会产生问题。 这可能会干扰依赖于隐式转换的复制构造函数和其他单参数构造函数。

所以必须限制只能获取档案。

有不同的方法可以做到这一点,但基于此对话http://marc.info/?l=boost&m=121131260728308&w=2,并且archives 的继承树 记录了http://www.boost.org/doc/libs/1_35_0/libs/serialization/doc/class_diagram.html,我认为这是最好的解决方案是检查参数是否来自basic_iarchive

#include<type_traits>
struct Foo 
    ...
    std::vector<int> data;    
    Foo() 
        // populate "data" by doing calculation
        data.push_back(1); data.push_back(2);
    

    template<class IArchive, 
        typename = std::enable_if_t<std::is_base_of<boost::archive::detail::basic_iarchive, IArchive>::value>>
    Foo( IArchive & ar ) 
        ar >> data;
        // populate "data" by reading the archive
    
    ...    
;

int main(int argc, const char *argv[])

    // deserialize
    boost::archive::text_iarchive iar(std::cin); 
    Foo foo(iar); // will also work with other archives

至于当您的数据不是默认构造时会发生什么,请参阅上面的讨论。

【讨论】:

以上是关于从 boost 序列化档案中构造对象的主要内容,如果未能解决你的问题,请参考以下文章

C++ Boost 序列化、构造函数和数据复制

Boost - 使用 TLV 编码序列化字符串

Boost序列化版本信息

提高序列化保存到多种存档类型,并防止在使用指针加载时构造新对象

哪个流适合通过UDP进行序列化?

使用Boost将派生类部分反序列化为基类时输入流错误