类的包装指针的Boost序列化
我有一个包装指针的类Ptr
。 这个指针可以处理像Ptr<A>
这样的结构,其中A
可以是一个复杂的结构,或者是像Ptr<double>
这样的基元。 我想指定Ptr
系列化的save
和load
功能以适用于这两种情况。
在这里我尝试重现一个简化的例子:
struct A {
A(int aa) : a(aa) {}
int a;
template<class Archive>
void serialize(Archive &ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_NVP(a);
}
};
template <typename T>
struct Ptr {
Ptr() : m_elem(0) {}
Ptr(const T* elem) { m_elem = (elem ? new T(*elem) : 0); };
const T& operator*() const { return *m_elem; };
T& operator*() { return *m_elem; };
const T* operator->() const { return m_elem;};
T* operator->() { return m_elem;};
// [...] other ctor, copy, del, etc...
T* m_elem;
};
namespace boost { namespace serialization {
template<class Archive, class T>
void save(Archive & ar, const Ptr<T> &ptr, const unsigned int version) {
T* base_pointer = (ptr.m_elem);
ar & boost::serialization::make_nvp("Ptr", base_pointer);
}
template<class Archive, class T>
void load(Archive & ar, Ptr<T> &ptr, const unsigned int version) {
T *base_pointer;
ar & boost::serialization::make_nvp("Ptr", base_pointer);
ptr.m_elem = base_pointer;
}
template<class Archive, class T>
void serialize(Archive & ar, Ptr<T> &ptr, const unsigned int version)
{
boost::serialization::split_free(ar, ptr, version);
}
}} // end namespace
int main() {
Ptr<A> p1(new A(4));
std::cout << p1.m_elem->a << std::endl;
Ptr<double> p2(new double(2.0));
std::cout << *(p2.m_elem) << std::endl;
// The serialization for Ptr<A> seems to work
std::ostringstream archive_ostream;
boost::archive::xml_oarchive oa(archive_ostream);
oa << BOOST_SERIALIZATION_NVP(p1);
std::cout << archive_ostream.str() << std::endl;
// Serialization for Ptr<double> does not compile
/*
std::ostringstream archive_ostream2;
boost::archive::xml_oarchive oa2(archive_ostream2);
oa2 << BOOST_SERIALIZATION_NVP(p2);
std::cout << archive_ostream2.str() << std::endl;
*/
}
现场示例
正如你所看到的, Ptr<A>
的序列化似乎可行(但我不确定它是否足够安全)。 但是, Ptr<double>
序列化不会编译。
错误输出是:
main.cpp:在'void boost :: serialization :: save(Archive&,const Ptr&,unsigned int)的实例化中[with Archive = boost :: archive :: xml_oarchive; T = A]':
/usr/local/include/boost/serialization/split_free.hpp:45:13:
需要从'静态无效boost ::序列化:: free_saver :: invoke(存档&,const T&,unsigned int)[与存档= boost :: archive :: xml_oarchive; T = Ptr]'
/usr/local/include/boost/serialization/split_free.hpp:74:18:
需要从'void boost :: serialization :: split_free(Archive&,T&,unsigned int)[with Archive = boost :: archive :: xml_oarchive; T = Ptr]'
main.cpp:57:34:需要从'void boost :: serialization :: serialize(Archive&,Ptr&,unsigned int)[with Archive = boost :: archive :: xml_oarchive; T = A]'
因此我正在寻找一个正确的Ptr
序列化!
谜题的解决方案就是不支持通过指针序列化基元类型。
原因是原始类型的对象跟踪被禁用。 这里记录如下:
特殊考虑/对象跟踪
默认情况下,实现级别序列化特征指定的原始数据类型不会被跟踪。 如果需要通过指针(例如,用作引用计数的长整型)跟踪共享原语对象,则应将其包装在类/结构中,以便它是可识别的类型。 改变一个多头的执行水平的替代方案会影响整个程序中的所有多头头衔 - 可能不是人们想要的。
这是一个简单的例子,它显示了孤立的根本原因:
住在Coliru
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <iostream>
#include <sstream>
int main() {
// Serialization for double* does not compile
double* p(new double(2.0));
std::cout << *p << std::endl;
std::ostringstream oss;
boost::archive::xml_oarchive oa(oss);
oa << BOOST_SERIALIZATION_NVP(p);
std::cout << oss.str() << std::endl;
}
你需要重新考虑你的序列化计划。 你希望/需要追踪什么对象身份?
您可以跟踪Ptr<>
对象的身份,并且由于您不费力地实现自定义指针包装器类型,我得到的印象是这很可能就是您所需要的。
演示: 直播Coliru
在极少数情况下,您确实需要双层对象跟踪(例如,如果可以有两个Ptr<T>
实例指向相同的T
?),您需要部分专门针对T是基本类型的情况。
上一篇: Boost serialization of class wrapping a pointer
下一篇: XML Serialization with C++ Boost: how to refer to the base class?