I want to serialize the following class wrapping a pointer which can handle a null m_element as you can see when calling the default constructor. This follows this question.
template <typename T>
struct Ptr { // Ptr could use init constructor here but this is not the point
Ptr() { m_elem = 0; }
Ptr(const T* elem) {
if (elem)
m_elem = new T(*elem);
else
m_elem = 0;
}
Ptr(const T& elem)
{
m_elem = new T(elem);
}
Ptr(const Ptr& elem)
{
if (elem.m_elem)
m_elem = new T(*(elem.m_elem));
else
m_elem = 0;
}
virtual ~Ptr() { delete m_elem; m_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; };
T* m_elem;
};
namespace boost { namespace serialization {
// Not sure about the approach to manage null m_elem here
template<class Archive, class T>
void save(Archive & ar, const Ptr<T> &ptr, const unsigned int version)
{
T elem = 0;
if (ptr.m_elem != 0)
ar& boost::serialization::make_nvp("data", *ptr.m_elem);
else
ar& boost::serialization::make_nvp("data", elem);
}
// How to implement load ?
template<class Archive, class T>
void load(Archive & ar, Ptr<T> &ptr, const unsigned int version)
{
ar& boost::serialization::make_nvp("data", *ptr.m_elem);
}
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> p;
std::ostringstream oss;
boost::archive::xml_oarchive oa(oss);
oa << BOOST_SERIALIZATION_NVP(p);
std::cout << oss.str() << std::endl;
// segfault
Ptr<double> po;
std::istringstream iss;
iss.str(oss.str());
boost::archive::xml_iarchive ia(iss);
ia >> BOOST_SERIALIZATION_NVP(po);
}
{
Ptr<double> p(new double(2.0));
std::cout << *(p.m_elem) << std::endl;
std::ostringstream oss;
boost::archive::xml_oarchive oa(oss);
oa << BOOST_SERIALIZATION_NVP(p);
std::cout << oss.str() << std::endl;
// segfault
Ptr<double> po;
std::istringstream iss;
iss.str(oss.str());
boost::archive::xml_iarchive ia(iss);
ia >> BOOST_SERIALIZATION_NVP(po);
}
}
The serialization seems to work but the deserialization gives a segfault. I am working in C++0x.
- How can I provide safe save and load functions to serialize Ptr without changing Ptr if possible ?
- If I need to modify Ptr, what do you propose ?
Edit : thanks to Jarod42 comment I came up with the following save/load functions using a boolean to detect null pointer or not. Now I do not have a segfault anymore when m_elem
is null but I have a one when it is not null.
template<class Archive, class T>
void save(Archive & ar, const Ptr<T> &ptr, const unsigned int version)
{
bool is_null;
if (ptr.m_elem != 0) {
is_null = false;
ar& boost::serialization::make_nvp("is_null", is_null);
ar& boost::serialization::make_nvp("data", *ptr.m_elem);
}
else
{
is_null = true;
ar& boost::serialization::make_nvp("is_null", is_null);
}
}
template<class Archive, class T>
void load(Archive & ar, Ptr<T> &ptr, const unsigned int version)
{
bool is_null;
ar& boost::serialization::make_nvp("is_null", is_null);
if (is_null == true) {
ptr.m_elem = 0;
}
else
{
ar& boost::serialization::make_nvp("data", *ptr.m_elem);
}
}