// This demonstrates a problem with boost::serialization and boost::enable_shared_from_this. // (boost version 1.53) // See boost TRAC ticket #9567 // // Given the following class structure: // Base is a simple class // Derived inherits from Base // Derived also inherits from boost::enable_shared_from_this // Base and Derived implement boost::serialization // // When deserializing an instance of Derived into a vector of boost::shared_ptr: // Base and Derived members are reconstructed correctly. // Derived::shared_from_this() works as expected. // // But when deserializing an instance of Derived into a vector of boost::shared_ptr: // Base and Derived members are still reconstructed correctly. // Derived::shared_from_this() throws a bad_weak_ptr exception. // This is because enable_shared_from_this::weak_ptr is NOT reconstructed - It is zero. #define BOOST_TEST_MAIN #include #include #include #include #include #include #include #include #include #include class Base { public: Base() {} virtual ~Base() {} // "virtual" forces RTTI, to enable serialization of Derived from Base pointer int m_base; template void serialize(Archive & ar, const unsigned int version) { ar & BOOST_SERIALIZATION_NVP(m_base); } }; class Derived : public Base, public boost::enable_shared_from_this { public: Derived() {} ~Derived() {} boost::shared_ptr SharedPtr() { return shared_from_this(); } int m_derived; template void serialize(Archive & ar, const unsigned int version) { ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); ar & BOOST_SERIALIZATION_NVP(m_derived); } }; // The following is required to enable serialization from Base pointer BOOST_CLASS_EXPORT(Derived) BOOST_AUTO_TEST_SUITE(test_shared_from_this) // This test passes BOOST_AUTO_TEST_CASE(deserialize_pointer_Derived) { std::stringstream ss; { // Create a vector of shared_ptr containing an instance of shared_ptr std::vector> vec_d; boost::shared_ptr d(new Derived()); d->m_base = 1; d->m_derived = 2; vec_d.push_back(d); d.reset(); // Get a raw pointer to Derived Derived* raw_d = vec_d[0].get(); // Verify base and derived members BOOST_CHECK(raw_d->m_base==1); BOOST_CHECK(raw_d->m_derived==2); // verify shared_from_this d = raw_d->SharedPtr(); BOOST_CHECK(d == vec_d[0]); // Serialize the vector boost::archive::xml_oarchive oa(ss); oa & BOOST_SERIALIZATION_NVP(vec_d); } { // Deserialize it back into a vector of shared_ptr std::vector> vec_d; ss.seekg(0); boost::archive::xml_iarchive ia(ss); ia & BOOST_SERIALIZATION_NVP(vec_d); // Get a raw pointer to Derived Derived* raw_d = vec_d[0].get(); // Verify base and derived members BOOST_CHECK(raw_d->m_base==1); BOOST_CHECK(raw_d->m_derived==2); // verify shared_from_this boost::shared_ptr d = raw_d->SharedPtr(); BOOST_CHECK(d == vec_d[0]); } } // This test fails BOOST_AUTO_TEST_CASE(deserialize_vector_Base) { std::stringstream ss; { // Create a vector of shared_ptr containing an instance of shared_ptr std::vector> vec_b; boost::shared_ptr b(new Derived()); Derived* raw_d1 = static_cast(b.get()); raw_d1->m_base = 1; raw_d1->m_derived = 2; vec_b.push_back(b); // Get a raw pointer to Derived via shared_ptr Derived* raw_d = static_cast(vec_b[0].get()); // Verify base and derived members BOOST_CHECK(raw_d->m_base==1); BOOST_CHECK(raw_d->m_derived==2); // verify shared_from_this boost::shared_ptr d = raw_d->SharedPtr(); BOOST_CHECK(d == vec_b[0]); // Serialize the vector boost::archive::xml_oarchive oa(ss); oa & BOOST_SERIALIZATION_NVP(vec_b); } { // Deserialize it back into a vector of shared_ptr std::vector> vec_b; ss.seekg(0); boost::archive::xml_iarchive ia(ss); ia & BOOST_SERIALIZATION_NVP(vec_b); // Get a raw pointer to Derived via shared_ptr Derived* raw_d = static_cast(vec_b[0].get()); // Verify base and derived members BOOST_CHECK(raw_d->m_base==1); BOOST_CHECK(raw_d->m_derived==2); // verify shared_from_this // FAIL: The following line throws bad_weak_ptr exception boost::shared_ptr d = raw_d->SharedPtr(); BOOST_CHECK(d == vec_b[0]); } } // This test demonstrates a workaround by reconstructing the weak_ptr after deserialization BOOST_AUTO_TEST_CASE(deserialize_vector_Base_workaround) { std::stringstream ss; { // Create a vector of shared_ptr containing an instance of shared_ptr std::vector> vec_b; boost::shared_ptr b(new Derived()); Derived* raw_d1 = static_cast(b.get()); raw_d1->m_base = 1; raw_d1->m_derived = 2; vec_b.push_back(b); // Get a raw pointer to Derived via shared_ptr Derived* raw_d = static_cast(vec_b[0].get()); // Verify base and derived members BOOST_CHECK(raw_d->m_base==1); BOOST_CHECK(raw_d->m_derived==2); // verify shared_from_this boost::shared_ptr d = raw_d->SharedPtr(); BOOST_CHECK(d == vec_b[0]); // Serialize the vector boost::archive::xml_oarchive oa(ss); oa & BOOST_SERIALIZATION_NVP(vec_b); } { // Deserialize it back into a vector of shared_ptr std::vector> vec_b; ss.seekg(0); boost::archive::xml_iarchive ia(ss); ia & BOOST_SERIALIZATION_NVP(vec_b); // Get a raw pointer to Derived via shared_ptr Derived* raw_d = static_cast(vec_b[0].get()); // Verify base and derived members BOOST_CHECK(raw_d->m_base==1); BOOST_CHECK(raw_d->m_derived==2); // WORKAROUND: reconstruct enable_shared_from_this weak_ptr raw_d->_internal_accept_owner(&vec_b[0], raw_d); // verify shared_from_this boost::shared_ptr d = raw_d->SharedPtr(); BOOST_CHECK(d == vec_b[0]); } } BOOST_AUTO_TEST_SUITE_END()