gpt4 book ai didi

c++ - boost 非默认构造类型的序列化

转载 作者:行者123 更新时间:2023-11-30 03:47:48 29 4
gpt4 key购买 nike

我正在使用 boost 序列化 1.40 序列化一个具有非默认构造函数的类。让我们说

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

我想要:

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

这是(反)序列化对应该实现的类的引用的方式吗?虽然我在这里发现了 (load)save_construct_data 用于 (de) 序列化指向非默认可构造类的指针的用法:

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

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

最佳答案

文档说明了原因:

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.

框架不可能计算出引用的生命周期/所有权语义。需要手动“引导”引用:您需要弄清楚谁拥有该实例并将任何重要的引用序列化为指针。

这有很多问题,序列化引用很少是个好主意[1]。主要是引用无法重新定位。

这意味着引用必须在构造时绑定(bind),对(反)序列化顺序提出严格要求。

当引用在逻辑上不是归档的一部分的“外部”实体(例如全局配置、父节点和其他簿记开销)时,引用通常是“ok”的。但在这种情况下,您希望独立于存档数据来设置引用。

如果不是这种情况,请重新考虑您的设计。

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] 我认为在你的类(class)中有引用成员很少是个好主意

更新

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

}

打印

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

另见这个较旧的答案:

关于c++ - boost 非默认构造类型的序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33505615/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com