Boost serialization of class wrapping a pointer
I have a class Ptr
which wraps a pointer. This pointer can handle structures such as Ptr<A>
where A
can be a complex structure or primitives such as Ptr<double>
. I would like to specify the save
and load
functions of Ptr
serilaization to work for both of these cases.
Here I try to reproduce a simplified example :
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;
*/
}
Live example
As you can see, the serialization for Ptr<A>
seems to work (still I am not sure if it is safe enough). However, serialization for Ptr<double>
is not compiling.
Error output is :
main.cpp: In instantiation of '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:
required from 'static void boost::serialization::free_saver::invoke(Archive&, const T&, unsigned int) [with Archive = boost::archive::xml_oarchive; T = Ptr]'
/usr/local/include/boost/serialization/split_free.hpp:74:18:
required from 'void boost::serialization::split_free(Archive&, T&, unsigned int) [with Archive = boost::archive::xml_oarchive; T = Ptr]'
main.cpp:57:34: required from 'void boost::serialization::serialize(Archive&, Ptr&, unsigned int) [with Archive = boost::archive::xml_oarchive; T = A]'
Hence I am looking for a correct Ptr
serialization !
The solution to the riddle is simply that serializing primitive types through a pointer is not supported.
The reason is that object tracking is disabled for primitive types. this is documented here:
Special Considerations / Object Tracking
By default, data types designated primitive by Implementation Level class serialization trait are never tracked. If it is desired to track a shared primitive object through a pointer (eg a long used as a reference count), It should be wrapped in a class/struct so that it is an identifiable type. The alternative of changing the implementation level of a long would affect all longs serialized in the whole program - probably not what one would intend.
Here's a minimalist sample that shows the root cause in isolation:
Live On 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;
}
You need to rethink your serialization plan. What object identity do you wish/need to track?
You can track the identity of the Ptr<>
object, and from the fact that you took the trouble toimplement a custom pointer wrapper type, I get the impression that this is likely all you want/need.
Demo: Live On Coliru
In the unlikely event that you really want bi-level object tracking here (eg if you can have two Ptr<T>
instances pointing to the same T
?) you will need to partially specialize for the case where T is a primitive type.
上一篇: 1:错误:LNK2019:
下一篇: 类的包装指针的Boost序列化