【问题标题】:Construct object from boost serialization archive从 boost 序列化档案中构造对象
【发布时间】: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,您将默认构造函数与未初始化的变量混淆了。默认构造函数应该让您的对象处于有效状态(如果可能的话,也是可预测的状态)。

标签: c++ boost boost-serialization


【解决方案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
    }
    

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

    【讨论】:

      猜你喜欢
      • 2018-11-02
      • 2011-06-25
      • 1970-01-01
      • 2018-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多