
Hi. I have hit a problem with boost serialization (occurs in all versions of boost - 1.37.0 .. 1.45.0). Summary: I have virtual base class A, derived B, and an AMap class (also A-derived) which holds shared_ptr<A>'s. I get different data written out depending on whether I serialise out an AMap stored in a shared_ptr<A> or a shared_ptr<const A>, and in one case (non-const) I get a segfault on load. The following code illustrates the problem in entirety and is the simplest case I found which generates the problem (I tried several variations - saving the map directly, removing A as AMap's base class etc, etc, to no avail). You should be able to cut'n'paste and compile into a single executable. I am testing on linux + centOS. ############################################################################################################## lib.h #ifndef __TESTLIB__H_ #define __TESTLIB__H_ #include <map> #include <boost/serialization/nvp.hpp> #include <boost/serialization/shared_ptr.hpp> #include <boost/serialization/base_object.hpp> class A { public: A(){} virtual ~A(){} template<class Archive> void serialize(Archive & ar, const unsigned int version){} }; typedef boost::shared_ptr<A> a_ptr; typedef boost::shared_ptr<const A> c_a_ptr; typedef std::map<int, a_ptr> a_map; class B : public A{ public: B(){} virtual ~B(){} template<class Archive> void serialize(Archive & ar, const unsigned int version){ ar & boost::serialization::make_nvp("base_class", boost::serialization::base_object<A>(*this)); } }; class AMap : public A { public: AMap(){} virtual ~AMap(){} template<class Archive> void serialize(Archive & ar, const unsigned int version){ ar & boost::serialization::make_nvp("base_class_a", boost::serialization::base_object<A>(*this)); ar & boost::serialization::make_nvp("map", m_map); } a_map m_map; }; #endif ############################################################################################################## lib.cpp #include <boost/archive/xml_oarchive.hpp> #include <boost/archive/xml_iarchive.hpp> #include "lib.h" #include <boost/serialization/map.hpp> #include <boost/serialization/export.hpp> BOOST_CLASS_EXPORT(A); BOOST_CLASS_EXPORT(B); BOOST_CLASS_EXPORT(AMap); ############################################################################################################## main.cpp #include <boost/archive/xml_oarchive.hpp> #include <boost/archive/xml_iarchive.hpp> #include <boost/serialization/map.hpp> #include <fstream> #include <iostream> #include "lib.h" const char* fname="/tmp/testlib.xml"; void save(*a_ptr* a) // NOTE!!! change me to c_a_ptr to get a segfault on load { std::ofstream fs(fname); boost::archive::xml_oarchive ar(fs); ar & boost::serialization::make_nvp("root", a); } int main(int argc, char** argv) { { std::cout << "saving..." << std::endl; AMap* pam = new AMap(); a_ptr a(new B()); pam->m_map.insert(a_map::value_type(1, a)); a_ptr am(pam); save(am); } { std::cout << "loading..." << std::endl; a_ptr am; std::ifstream fs(fname); boost::archive::xml_iarchive ar(fs); ar & boost::serialization::make_nvp("root", am); assert(am); } return 0; } Note that changing main's save() arg to a shared_ptr<const A> changes the data written out. Here is an example xml archive resulting from saving via a non-const shared_ptr (the case that WORKS on load): <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <!DOCTYPE boost_serialization> <boost_serialization signature="serialization::archive" version="5"> <root class_id="0" tracking_level="0" version="1"> <px class_id="2" class_name="AMap" tracking_level="1" version="0" object_id="_0"> <base_class_a class_id="1" tracking_level="1" version="0" object_id="_1"></base_class_a> <base_class_map class_id="3" tracking_level="0" version="0"> <count>1</count> <item_version>0</item_version> <item class_id="4" tracking_level="0" version="0"> <first>1</first> <second> <px class_id="5" class_name="B" tracking_level="1" version="0" object_id="_2"> <base_class object_id="_3"></base_class> </px> </second> </item> </base_class_map> </px> </root> </boost_serialization> Here is the same data but written out via the CONST shared_ptr (the case that FAILS on load): <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <!DOCTYPE boost_serialization> <boost_serialization signature="serialization::archive" version="5"> <root class_id="0" tracking_level="0" version="1"> <px class_id="2" class_name="AMap" tracking_level="1" version="0" object_id="_0"> <base_class_a class_id="1" tracking_level="1" version="0" object_id="_1"></base_class_a> <base_class_map class_id="3" tracking_level="0" version="0"> <count>1</count> <item_version>0</item_version> <item class_id="4" tracking_level="0" version="0"> <first>1</first> <second *class_id="5" tracking_level="0" version="1"*> <px class_id="6" class_name="B" tracking_level="1" version="0" object_id="_2"> <base_class object_id="_3"></base_class> </px> </second> </item> </base_class_map> </px> </root> </boost_serialization> Note the difference, which I've put in bold. If somebody could explain what is happening here I'd be very grateful. Obviously something is going on with the object tracking... and what I find most strange is that the data that loads correctly actually looks incorrect (<second> doesn't have tracking-level=0, whereas tracking-level=0 wherever else there's a shared_ptr, as I'd expect). Note: I have tested using the xml and binary archives... xml segfaults, binary throws a stream_error. Thanks in advance Allan