test_enable_shared_from_this.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
  2. // test_enable_shared_from_this.cpp
  3. // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
  4. // Use, modification and distribution is subject to the Boost Software
  5. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. // This demonstrates a problem with boost::serialization and boost::enable_shared_from_this.
  8. // (boost version 1.53)
  9. // See boost TRAC ticket #9567
  10. //
  11. // Given the following class structure:
  12. // Base is a simple class
  13. // Derived inherits from Base
  14. // Derived also inherits from boost::enable_shared_from_this<Derived>
  15. // Base and Derived implement boost::serialization
  16. //
  17. // When deserializing an instance of Derived into a vector of boost::shared_ptr<Derived>:
  18. // Base and Derived members are reconstructed correctly.
  19. // Derived::shared_from_this() works as expected.
  20. //
  21. // But when deserializing an instance of Derived into a vector of boost::shared_ptr<Base>:
  22. // Base and Derived members are still reconstructed correctly.
  23. // Derived::shared_from_this() throws a bad_weak_ptr exception.
  24. // This is because enable_shared_from_this::weak_ptr is NOT reconstructed - It is zero.
  25. #include <sstream>
  26. #include <boost/archive/text_oarchive.hpp>
  27. #include <boost/archive/text_iarchive.hpp>
  28. #include <boost/enable_shared_from_this.hpp>
  29. #include <boost/serialization/shared_ptr.hpp>
  30. #include <boost/serialization/export.hpp>
  31. #include <boost/serialization/split_free.hpp>
  32. #include "test_tools.hpp"
  33. #include <set>
  34. namespace boost {
  35. namespace serialization {
  36. struct enable_shared_from_this_helper {
  37. std::set<shared_ptr<void> > m_esfth;
  38. void record(boost::shared_ptr<void> sp){
  39. m_esfth.insert(sp);
  40. }
  41. };
  42. template<class Archive, class T>
  43. void serialize(
  44. Archive & ar,
  45. boost::enable_shared_from_this<T> & t,
  46. const unsigned int file_version
  47. ){
  48. enable_shared_from_this_helper & h =
  49. ar.template get_helper<
  50. enable_shared_from_this_helper
  51. >();
  52. shared_ptr<T> sp = t.shared_from_this();
  53. h.record(sp);
  54. }
  55. } // serialization
  56. } // boost
  57. class Base {
  58. friend class boost::serialization::access;
  59. template<class Archive>
  60. void serialize(Archive & ar, const unsigned int version)
  61. {
  62. ar & BOOST_SERIALIZATION_NVP(m_base);
  63. }
  64. protected:
  65. Base() {}
  66. virtual ~Base() {} // "virtual" forces RTTI, to enable serialization of Derived from Base pointer
  67. public:
  68. int m_base;
  69. };
  70. class Derived : public Base, public boost::enable_shared_from_this<Derived> {
  71. friend class boost::serialization::access;
  72. template<class Archive>
  73. void serialize(Archive & ar, const unsigned int version)
  74. {
  75. ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
  76. ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(
  77. boost::enable_shared_from_this<Derived>
  78. );
  79. ar & BOOST_SERIALIZATION_NVP(m_derived);
  80. }
  81. public:
  82. boost::shared_ptr<Derived> SharedPtr() { return shared_from_this(); }
  83. int m_derived;
  84. Derived() {}
  85. ~Derived() {}
  86. };
  87. // The following is required to enable serialization from Base pointer
  88. BOOST_CLASS_EXPORT(Derived)
  89. // This test passes
  90. void test_passes(){
  91. std::stringstream ss;
  92. {
  93. boost::shared_ptr<Derived> d(new Derived());
  94. d->m_base = 1;
  95. d->m_derived = 2;
  96. // Get a raw pointer to Derived
  97. Derived* raw_d = d.get();
  98. // Verify base and derived members
  99. BOOST_CHECK(raw_d->m_base==1);
  100. BOOST_CHECK(raw_d->m_derived==2);
  101. // verify shared_from_this
  102. BOOST_CHECK(d == raw_d->SharedPtr());
  103. boost::archive::text_oarchive oa(ss);
  104. oa & BOOST_SERIALIZATION_NVP(d);
  105. }
  106. {
  107. // Deserialize it back into a vector of shared_ptr<Derived>
  108. boost::shared_ptr<Derived> d;
  109. ss.seekg(0);
  110. boost::archive::text_iarchive ia(ss);
  111. ia & BOOST_SERIALIZATION_NVP(d);
  112. // Get a raw pointer to Derived
  113. Derived* raw_d = d.get();
  114. // Verify base and derived members
  115. BOOST_CHECK(raw_d->m_base==1);
  116. BOOST_CHECK(raw_d->m_derived==2);
  117. // verify shared_from_this
  118. BOOST_CHECK(d == raw_d->SharedPtr());
  119. }
  120. }
  121. // This test fails
  122. void test_fails(){
  123. std::stringstream ss;
  124. {
  125. boost::shared_ptr<Base> b(new Derived());
  126. Derived* raw_d1 = static_cast<Derived*>(b.get());
  127. raw_d1->m_base = 1;
  128. raw_d1->m_derived = 2;
  129. // Get a raw pointer to Derived via shared_ptr<Base>
  130. Derived* raw_d = static_cast<Derived*>(b.get());
  131. // Verify base and derived members
  132. BOOST_CHECK(raw_d->m_base==1);
  133. BOOST_CHECK(raw_d->m_derived==2);
  134. // verify shared_from_this
  135. boost::shared_ptr<Derived> d = raw_d->SharedPtr();
  136. BOOST_CHECK(d == b);
  137. // Serialize the vector
  138. boost::archive::text_oarchive oa(ss);
  139. oa & BOOST_SERIALIZATION_NVP(b);
  140. }
  141. {
  142. // Deserialize it back into a vector of shared_ptr<Base>
  143. ss.seekg(0);
  144. boost::archive::text_iarchive ia(ss);
  145. boost::shared_ptr<Base> b;
  146. ia & BOOST_SERIALIZATION_NVP(b);
  147. // Get a raw pointer to Derived via shared_ptr<Base>
  148. Derived* raw_d = static_cast<Derived*>(b.get());
  149. // Verify base and derived members
  150. BOOST_CHECK(raw_d->m_base==1);
  151. BOOST_CHECK(raw_d->m_derived==2);
  152. // verify shared_from_this
  153. // FAIL: The following line throws bad_weak_ptr exception
  154. boost::shared_ptr<Derived> d = raw_d->SharedPtr();
  155. BOOST_CHECK(d == b);
  156. }
  157. }
  158. int test_main(int /*argc*/, char * /*argv */[]){
  159. test_fails();
  160. test_passes();
  161. return EXIT_SUCCESS;
  162. }
  163. // EOF