我正在序列化一个具有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);
}
} }
这是(de)序列化对应该实现的类的引用的方式吗?虽然我已经找到(load)save_construct_data用于(de)序列化指向非默认可构造类的指针:
http://www.boost.org/doc/libs/1_40_0/libs/serialization/doc/serialization.html#constructors
我还没有找到如何处理对这些类的引用。
答案 0 :(得分:2)
文档说明原因:
包含引用成员的类通常需要非默认值 构造函数作为引用只能在构造实例时设置。
如果班级有上一节的例子稍微复杂一点 参考成员。这提出了对象的方式和位置的问题 被引用被存储以及它们是如何被创建的。还有 关于引用多态基类的问题。基本上,这些都是 关于指针出现的相同问题。
这并不奇怪,因为引用实际上是一种特殊的指针。 我们 通过序列化引用来解决这些问题,就像它们一样 指针。 强>
框架不可能找出引用的生命周期/所有权语义。引用需要手动“引导”:您需要确定谁拥有实例并将任何重要引用序列化为指针。
这有很多问题,序列化引用 [1] 并不是一个好主意。主要是因为参考不能重新安排。
这意味着参考必须在施工时受到约束,对(反)序列化订单提出严格要求。
当引用“逻辑上不属于归档的”外部“实体(例如全局配置,父节点和其他簿记开销)时,引用通常是”正常的“。但在这种情况下,您希望独立于归档数据来实现参考。
每当情况不是这样时,请重新考虑您的设计。
注意所引用的文档继续显示如何强制反序列化引用的示例,但这使得所有权/生命周期的谜语完全打开,并且正如所写的那样保证内存泄漏。
对于非基本类型,您将在单个存档中获得对象跟踪(因此,别名引用的重复数据删除)。
[1] 我认为在班上有参考成员很少是个好主意
<强> 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
另见这个较旧的答案: