[serialization] Assertion failure with shared_ptr cycles

Hi,
I'm hitting an assert when I deserialize cycles of
shared_ptr<>s. I have the following class hierarchy:
Base <-- Derived
Other
Derived holds a shared_ptr<Other>, and Other holds a
shared_ptr<Base>.
I have an instance of Derived that points to an instance of
Other, which in turn points back to the Derived instance (as
a Base pointer). The serialization goes as expected. On
deserialization, however, the Base::serialize() and
Derived::serialize() are called repeatedly, crashing after
the third time -- Other::serialize() is never called.
This problem only happens when the cycle includes a pointer
to a base class -- a straightforward a -> b -> a cycle works
as expected.
Has anyone else experienced this or found a workaround? It
happens in both boost 1.36 and 1.37.0 beta1. I'm using gcc
(3.3.5, 3.4.6, and 4.3.2).
Thanks,
Ult
P.S. Attached is the source code illustrating the above
example. Here is the output:
Serializing...
Derived
Base
Base done
Other
Other done
Derived done
Deserializing...
Derived
Base
Base done
Derived
Base
Base done
Derived
cycles:
./boost_1_37_0_beta1/libs/serialization/src/basic_iarchive.cpp:436:
const boost::archive::detail::basic_pointer_iserializer*
boost::archive::detail::basic_iarchive_impl::load_pointer(boost::archive::detail::basic_iarchive&,
void*&, const
boost::archive::detail::basic_pointer_iserializer*, const
boost::archive::detail::basic_pointer_iserializer* (*)(const
boost::serialization::extended_type_info&)): Assertion
`new_cid == cid' failed.
Aborted
#include <fstream>
#include <iostream>
#include

A couple of suggestions. a) Make Base abstract by including something like virtual ~Base() = 0; This won't address this problem but it can catch accidental "slicing" in other cases. b) The default behavior is to track addresses (thereby detecting cycles, only if a type is serialized through a pointer. Since this doesnt' occur in this program, cycles won't be detected. use serialization traits to set "serialization tracking" always on for the type Base. Robert Ramey Ult Mundane wrote:
Hi,
I'm hitting an assert when I deserialize cycles of shared_ptr<>s. I have the following class hierarchy:
Base <-- Derived Other
Derived holds a shared_ptr<Other>, and Other holds a shared_ptr<Base>.
I have an instance of Derived that points to an instance of Other, which in turn points back to the Derived instance (as a Base pointer). The serialization goes as expected. On deserialization, however, the Base::serialize() and Derived::serialize() are called repeatedly, crashing after the third time -- Other::serialize() is never called.
This problem only happens when the cycle includes a pointer to a base class -- a straightforward a -> b -> a cycle works as expected.
Has anyone else experienced this or found a workaround? It happens in both boost 1.36 and 1.37.0 beta1. I'm using gcc (3.3.5, 3.4.6, and 4.3.2).
Thanks,
Ult
P.S. Attached is the source code illustrating the above example. Here is the output:
Serializing...
Derived Base Base done Other Other done Derived done
Deserializing...
Derived Base Base done Derived Base Base done Derived cycles: ./boost_1_37_0_beta1/libs/serialization/src/basic_iarchive.cpp:436: const boost::archive::detail::basic_pointer_iserializer* boost::archive::detail::basic_iarchive_impl::load_pointer(boost::archive::detail::basic_iarchive&, void*&, const boost::archive::detail::basic_pointer_iserializer*, const boost::archive::detail::basic_pointer_iserializer* (*)(const boost::serialization::extended_type_info&)): Assertion `new_cid == cid' failed. Aborted
#include <fstream> #include <iostream>
#include
#include #include
#include #include
// Forward declarations class Base; class Derived; class Other;
typedef boost::shared_ptr<Base> BaseRef; typedef boost::shared_ptr<Derived> DerivedRef; typedef boost::shared_ptr<Other> OtherRef;
// For debug output struct Debug { Debug(const char * name) : mName(name) { std::cout << std::string(++sIndentLevel, ' ') << mName << std::endl; }
~Debug() { std::cout << std::string(sIndentLevel--, ' ') << mName << " done" << std::endl; }
static int sIndentLevel; char const * mName; };
int Debug::sIndentLevel = 0;
// Base class Base { public: virtual ~Base() { }
template<class Archive> void serialize(Archive & ar, const unsigned int) { Debug d("Base"); } };
// Derived class Derived : public Base { public: void setOther(OtherRef other) { mOther = other; }
template<class Archive> void serialize(Archive & ar, const unsigned int) { Debug d("Derived");
ar & boost::serialization::base_object<Base>(*this); // This line is executed three times before a crash on deserialzation ar & mOther; // Code after here is never executed on deserialization }
OtherRef mOther; };
// Other class Other { public: void setBase(BaseRef base) { mBase = base; }
template<class Archive> void serialize(Archive & ar, const unsigned int) { Debug d("Other"); ar & mBase; }
BaseRef mBase; };
BOOST_CLASS_EXPORT(Derived);
// main int main(int /* argc */, char * /* argv */[]) { char const * fname = "cycles.text_archive";
std::cout << std::endl << "Serializing..." << std::endl << std::endl;
{ DerivedRef derived(new Derived()); OtherRef other(new Other());
derived->setOther(other); other->setBase(derived);
std::ofstream ofs(fname, std::ios::out | std::ios::binary); boost::archive::text_oarchive oa(ofs);
oa & derived; }
std::cout << std::endl << "Deserializing..." << std::endl << std::endl;
{ Derived derivedCopy;
std::ifstream ifs(fname, std::ios::in | std::ios::binary); boost::archive::text_iarchive ia(ifs);
ia & derivedCopy; } }
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (2)
-
Robert Ramey
-
Ult Mundane