非缺省构造类型的系列化提振 [英] boost serialization of non-default constructible types

查看:112
本文介绍了非缺省构造类型的系列化提振的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的序列化与系列化提升1.40非默认构造函数的类。比方说

  typedef结构{富
    富(中间体B):A(B){}
    int类型的;
} foo的;

和我想有:

 名字空间boost {
命名空间序列{模板<类归档和GT;
无效save_construct_data(归档&安培;归档,常量foo的*女,const的无符号整型版)
{
    归档和放大器; foo->一种;
}模板<类归档和GT;
无效load_construct_data(归档&安培;归档,富*女,const的无符号整型版)
{
    int类型的;
    归档和放大器;一个;
    ::新的(F)富(一);
}模板<类归档和GT;
无效保存(归档&安培;归档,常量富和放大器;标签,const的无符号整型版)
{
    ;
}模板<类归档和GT;
无效负载(归档&安培;归档,富&安培; F,const的无符号整型版)
{
    ;
}模板<类归档和GT;
无效连载(归档&安培;归档,富&安培; F,const的无符号整型版)
{
    提高::系列化:: split_free(存档,F版本);
}
}}

这是要实现序列化到一个假想的类的引用方式(DE)?虽然我已经找到(负载)save_construct_data的使用情况(反)序列化的指针在这里非缺省构造类:

http://www.boost.org/doc/libs/1_40_0/libs/serialization/doc/serialization.html#constructors

我还没有找到如何处理这些类的引用。


解决方案

文档状态的原因:


  


  
  

这包含引用成员的类通常需要非默认
  当一个实例构造构造作为参照,才可以设置。


  
  的 previous部分的例子是,如果类具有稍微更复杂
  参考成员。这就提出了一个如何以及在何处对象的问题
  被称为存储以及如何他们创造。也有在
  即将多态基类的引用问题。基本上,这些都是
  出现的关于指针同样的问题。


  
  

这是毫不奇怪的引用是真是一种特殊的指针。 我们
  通过他们仿佛是序列化的引用解决这些问题
  指针。


该框架不可能弄清楚引用寿命/所有权语义。参考文献需要手动指导:你需要找出谁拥有实例和系列化任何显著的引用,如果指针。

有这个这么多的问题,这是很少一个好主意,序列化引用 [1] 。主要的事实,引用不能被重新插拔一下。

这意味着引用必须处于施工时间约束,气势(反)序列顺序严格的要求。

引用通常是OK时,他们指的外部的实体不属于逻辑上的存档(例如全局配置,父节点和其他簿记开销)的一部分。但是,在这种情况下,你希望instate独立的归档数据的引用。

每当这个情况并非如此,重新考虑你的设计。


  

注意引用文档接着显示如何强制引用的反序列化,而是一个例子这留下的所有权/寿命谜语完全开放,并作为写的保证内存泄漏。


  
  

对于非基本类型,你会得到目标跟踪(因此,别名引用的重复数据删除)的单个档案中



[1] 我认为,这是很少一个好主意,有参考成员在你的类

更新

<大骨节病> 住在Coliru

 的#include&LT;升压/存档/ text_oarchive.hpp&GT;
#包括LT&;升压/存档/ text_iarchive.hpp&GT;
#包括LT&;升压/系列化/ serialization.hpp&GT;
#包括LT&;升压/系列化/ vector.hpp&GT;
#包括LT&;升压/ ptr_container / ptr_vector.hpp&GT;
#包括LT&;升压/ ptr_container / serialize_ptr_vector.hpp&GT;
#包括LT&;集&gt;
#包括LT&;&iostream的GT;结构foo的{
    富(中间体B):A(B){}
    int类型的;
    INT B = 42;
};结构refholder {
    富&安培; _ref;
    refholder(富&安培; REF):_ref(REF){}
};命名空间{
    使用FooHandle =的std ::的unique_ptr&LT;富取代;
    静态的std ::设为&LT; FooHandle&GT; _instances;    FooHandle常量和放大器; register_instance(* foo的原料){
        / *外部管理一生,忽略易受骗的人,因为对象跟踪功能可以
         *导致使用相同的指针&gt;完成
         * /
        汽车现有=的std :: find_if(_instances.begin(),_instances.end()
                [RAW](FooHandle常量和放大器; P){返回原== p.get(); });        如果(现有== _instances.end())
            返回* _instances.insert(的std ::的unique_ptr&LT;富&GT;(原始))第一。
        其他
            返回*存在;
    }
}名字空间boost {
命名空间序列{    /// {{{foo的系列化
    模板&LT;类归档和GT;无效save_construct_data(归档和放大器; AR,常量foo的*女,const的无符号整型/ *版* /){
        AR&安培; F-&gt;一种;
    }    模板&LT;类归档和GT;无效load_construct_data(归档和放大器; AR,富*女,const的无符号整型/ *版* /){
        int类型的;
        AR&放大器;一个;
        ::新的(F)富(一);
    }    模板&LT;类归档和GT;无效连载(归档和放大器; AR,富&安培; F,const的无符号整型/ *版* /){AR&安培; f.b; }
    //}}}富系列化    /// {{{refholder系列化
    模板&LT;类归档和GT;无效save_construct_data(归档和放大器; AR,常量refholder * RH,const的无符号整型/ *版* /){
        * foo的外部=放大器; RH-&GT; _ref;
        AR&安培;外部;
    }    模板&LT;类归档和GT;无效load_construct_data(归档和放大器; AR,refholder * RH,const的无符号整型/ *版* /){
        * foo的外部= nullptr;
        AR&安培;外部;        register_instance(外部);        ::新(RH)refholder(*外); //通过取消引用外部指针。
    }    模板&LT;类归档和GT;无效连载(归档和放大器;,&refholder放大器;,const的无符号整型/ *版* /){
    }
    //}}} refholder系列化
}
}#包括LT&;&sstream GT;诠释主(){    的std :: stringstream的SS;
    使用data_t =的boost :: ptr_vector&LT; refholder取代;    {
        提高::档案:: text_oarchive的OA(SS);        富shared1(7),shared2(77);        data_t数据;
        data.push_back(新refholder {shared1}); data.push_back(新refholder {shared1}); data.push_back(新refholder {shared1});
        data.push_back(新refholder {shared2}); data.push_back(新refholder {shared2});        OA&LT;&LT;数据;
    }    性病::法院LT&;&LT; ss.str();    {
        断言(_instances.empty());        提高::档案:: text_iarchive IA(SS);        data_t数据;
        IA&GT;&GT;数据;        性病::法院LT&;&LT; _instances.size():&所述;&下; _instances.size()&所述;&下; \\ n;
        断言(_instances.size()== 2); //两个独特的实例
    }    // _instances将破坏,导致泄漏 - 自由}

打印

  22 ::系列化存档13 0 0 5 1 1 0
0 2 1 0
1 7 1 42
2 2 1 1
3 2 1 1
4 2
5 77 42 1
6 2 5
_instances.size():2

也看到这个旧的答案:


  • <一个href=\"http://stackoverflow.com/questions/32407426/boost-serialization-of-reference-member-abstract-class/32408107#32408107\">Boost参考成员抽象类系列化


  • <一个href=\"http://stackoverflow.com/questions/31256298/boost-serialization-save-construct-data-not-called/31257041#31257041\">boost序列化:save_construct_data不叫


  • 我居然遇到了这个标准libraryimplementation相关的问题(再次):<一href=\"http://stackoverflow.com/questions/30426543/boostserialization-object-with-private-default-constructor-works-in-a-vector/30437785#30437785\">boost::serialization:私人默认的构造函数对象在工作载体,但不是在一个地图


I am serializing a class that has a non-default constructor with boost serialization 1.40. Lets say

typedef struct foo {
    foo(int b) : a(b) {}
    int a;
} foo;

And I would like to have:

namespace boost {
namespace serialization {

template<class Archive>
void save_construct_data(Archive& archive, const foo* f, const unsigned int version)
{
    archive & foo->a;
}

template<class Archive>
void load_construct_data(Archive& archive, foo* f, const unsigned int version)
{
    int a;
    archive & a;
    ::new(f)foo(a);
}

template<class Archive>
void save(Archive& archive, const foo& label, const unsigned int version)
{
    ;
}

template<class Archive>
void load(Archive& archive, foo& f, const unsigned int version)
{
    ;
}

template<class Archive>
void serialize(Archive& archive, foo& f, const unsigned int version)
{
    boost::serialization::split_free(archive, f, version);
}
} }

Is this the way (de)serializing a reference to a class supposed to be implemented? While I have found usage of (load)save_construct_data for (de)serializing pointers to non-default constructible classes here:

http://www.boost.org/doc/libs/1_40_0/libs/serialization/doc/serialization.html#constructors

I have not found how to deal with references to those classes.

解决方案

The documentation states the reason:

References

Classes that contain reference members will generally require non-default constructors as references can only be set when an instance is constructed.

The example of the previous section is slightly more complex if the class has reference members. This raises the question of how and where the objects being referred to are stored and how are they created. Also there is the question about references to polymorphic base classes. Basically, these are the same questions that arise regarding pointers.

This is no surprise as references are really a special kind of pointer. We address these questions by serializing references as though they were pointers.

The framework cannot possibly figure out the lifetime/ownership semantics for references. References need to be manually "guided": you need to figure out who own the instance and serialize any significant references as if pointers.

There are so many issues with this, that it's rarely a good idea to serialize references[1]. Mainly with the fact that references can not be reseated.

This means the reference must be bound at construction time, imposing strict requirements on the (de)serialization order.

References are usually "ok" when they refer to "external" entities that are not logically part of the archive (e.g. global configuration, parent nodes and other bookkeeping overhead). But in such case you'd expect to instate the references independent of the archive data.

Whenever this is not the case, reconsider your design.

CAUTION The documentation cited goes on to show an example of how to force deserialization of references, but this leaves the ownership/lifetime riddle completely open, and as written is a guaranteed memory leak.

For non-primitive types, you will get object tracking (and hence, deduplication of aliased references) within a single archive.


[1] I'd argue that it's rarely a good idea to have reference members in your class

UPDATE

Live On Coliru

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/ptr_container/serialize_ptr_vector.hpp>
#include <set>
#include <iostream>

struct foo {
    foo(int b) : a(b) {}
    int a;
    int b = 42;
};

struct refholder {
    foo& _ref;
    refholder(foo& ref) : _ref(ref) {}
};

namespace {
    using FooHandle = std::unique_ptr<foo>;
    static std::set<FooHandle> _instances;

    FooHandle const& register_instance(foo* raw) {
        /* manage lifetime externally, ignore dupes because object tracking can
         * lead to same pointer used >once
         */
        auto existing = std::find_if(_instances.begin(), _instances.end(),
                [raw](FooHandle const& p) { return raw == p.get(); });

        if (existing == _instances.end())
            return *_instances.insert(std::unique_ptr<foo>(raw)).first;
        else
            return *existing;
    }
}

namespace boost {
namespace serialization {

    /// {{{ foo serialization
    template <class Archive> void save_construct_data(Archive &ar, const foo *f, const unsigned int /*version*/) {
        ar & f->a;
    }

    template <class Archive> void load_construct_data(Archive &ar, foo *f, const unsigned int /*version*/) {
        int a;
        ar &a;
        ::new (f) foo(a);
    }

    template <class Archive> void serialize(Archive &ar, foo &f, const unsigned int /*version*/) { ar & f.b; }
    // }}} foo serialization

    /// {{{ refholder serialization
    template <class Archive> void save_construct_data(Archive &ar, const refholder *rh, const unsigned int /*version*/) {
        foo* external = &rh->_ref;
        ar & external;
    }

    template <class Archive> void load_construct_data(Archive &ar, refholder *rh, const unsigned int /*version*/) {
        foo* external = nullptr;
        ar & external;

        register_instance(external);

        ::new (rh) refholder(*external); // pass the dereferenced external pointer.
    }

    template <class Archive> void serialize(Archive &, refholder&, const unsigned int /*version*/) {
    }
    // }}} refholder serialization
}
}

#include <sstream>

int main() {

    std::stringstream ss;
    using data_t = boost::ptr_vector<refholder>;

    {
        boost::archive::text_oarchive oa(ss);

        foo shared1(7), shared2(77);

        data_t data;
        data.push_back(new refholder{shared1}); data.push_back(new refholder{shared1}); data.push_back(new refholder{shared1});
        data.push_back(new refholder{shared2}); data.push_back(new refholder{shared2});

        oa << data;
    }

    std::cout << ss.str();

    {
        assert(_instances.empty());

        boost::archive::text_iarchive ia(ss);

        data_t data;
        ia >> data;

        std::cout << "_instances.size(): " << _instances.size() << "\n";
        assert(_instances.size() == 2); // two unique instances
    }

    // _instances will be destructed, leading to leak-free

}

Prints

22 serialization::archive 13 0 0 5 1 1 0
0 2 1 0
1 7 42 1
2 2 1 1
3 2 1 1
4 2
5 77 42 1
6 2 5
_instances.size(): 2

See also this older answer:

这篇关于非缺省构造类型的系列化提振的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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