Ticket #9567: test_shared_from_this.cpp

File test_shared_from_this.cpp, 4.8 KB (added by t_regan@…, 9 years ago)

Test demonstrating enable_shared_from_this deserialization problem

Line 
1// This demonstrates a problem with boost::serialization and boost::enable_shared_from_this.
2// (boost version 1.53)
3//
4// Given the following class structure:
5// Base is a simple class
6// Derived inherits from Base
7// Derived also inherits from boost::enable_shared_from_this<Derived>
8// Base and Derived implement boost::serialization
9//
10// When deserializing an instance of Derived into a vector of boost::shared_ptr<Derived>:
11// Base and Derived members are reconstructed correctly.
12// Derived::shared_from_this() works as expected.
13//
14// But when deserializing an instance of Derived into a vector of boost::shared_ptr<Base>:
15// Base and Derived members are still reconstructed correctly.
16// Derived::shared_from_this() throws a bad_weak_ptr exception.
17// This is because enable_shared_from_this::weak_ptr is NOT reconstructed - It is zero.
18#define BOOST_TEST_MAIN
19#include <boost/test/unit_test.hpp>
20#include <boost/test/output_test_stream.hpp>
21#include <vector>
22#include <boost/shared_ptr.hpp>
23#include <boost/enable_shared_from_this.hpp>
24#include <boost/serialization/shared_ptr.hpp>
25#include <boost/archive/xml_oarchive.hpp>
26#include <boost/archive/xml_iarchive.hpp>
27#include <boost/serialization/vector.hpp>
28#include <boost/serialization/export.hpp>
29
30class Base {
31public:
32 Base() {}
33 virtual ~Base() {} // "virtual" forces RTTI, to enable serialization of Derived from Base pointer
34 int m_base;
35
36 template<class Archive>
37 void serialize(Archive & ar, const unsigned int version)
38 {
39 ar & BOOST_SERIALIZATION_NVP(m_base);
40 }
41};
42
43class Derived : public Base, public boost::enable_shared_from_this<Derived> {
44public:
45 Derived() {}
46 ~Derived() {}
47 boost::shared_ptr<Derived> SharedPtr() { return shared_from_this(); }
48 int m_derived;
49
50 template<class Archive>
51 void serialize(Archive & ar, const unsigned int version)
52 {
53 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
54 ar & BOOST_SERIALIZATION_NVP(m_derived);
55 }
56};
57// The following is required to enable serialization from Base pointer
58BOOST_CLASS_EXPORT(Derived)
59
60BOOST_AUTO_TEST_SUITE(test_shared_from_this)
61
62// This test passes
63BOOST_AUTO_TEST_CASE(deserialize_pointer_Derived)
64{
65 std::stringstream ss;
66
67 {
68 // Create a vector of shared_ptr<Derived> containing an instance of shared_ptr<Derived>
69 std::vector<boost::shared_ptr<Derived>> vec_d;
70 boost::shared_ptr<Derived> d(new Derived());
71 d->m_base = 1;
72 d->m_derived = 2;
73 vec_d.push_back(d);
74 d.reset();
75
76 // Get a raw pointer to Derived
77 Derived* raw_d = vec_d[0].get();
78
79 // Verify base and derived members
80 BOOST_CHECK(raw_d->m_base==1);
81 BOOST_CHECK(raw_d->m_derived==2);
82
83 // verify shared_from_this
84 d = raw_d->SharedPtr();
85 BOOST_CHECK(d == vec_d[0]);
86
87 // Serialize the vector
88 boost::archive::xml_oarchive oa(ss);
89 oa & BOOST_SERIALIZATION_NVP(vec_d);
90 }
91 {
92 // Deserialize it back into a vector of shared_ptr<Derived>
93 std::vector<boost::shared_ptr<Derived>> vec_d;
94 ss.seekg(0);
95 boost::archive::xml_iarchive ia(ss);
96 ia & BOOST_SERIALIZATION_NVP(vec_d);
97
98 // Get a raw pointer to Derived
99 Derived* raw_d = vec_d[0].get();
100
101 // Verify base and derived members
102 BOOST_CHECK(raw_d->m_base==1);
103 BOOST_CHECK(raw_d->m_derived==2);
104
105 // verify shared_from_this
106 boost::shared_ptr<Derived> d = raw_d->SharedPtr();
107 BOOST_CHECK(d == vec_d[0]);
108 }
109}
110
111// This test fails
112BOOST_AUTO_TEST_CASE(deserialize_vector_Base)
113{
114 std::stringstream ss;
115
116 {
117 // Create a vector of shared_ptr<Base> containing an instance of shared_ptr<Derived>
118 std::vector<boost::shared_ptr<Base>> vec_b;
119 boost::shared_ptr<Derived> d(new Derived());
120 d->m_base = 1;
121 d->m_derived = 2;
122 vec_b.push_back(d);
123 d.reset();
124
125 // Get a raw pointer to Derived via shared_ptr<Base>
126 Derived* raw_d = static_cast<Derived*>(vec_b[0].get());
127
128 // Verify base and derived members
129 BOOST_CHECK(raw_d->m_base==1);
130 BOOST_CHECK(raw_d->m_derived==2);
131
132 // verify shared_from_this
133 d = raw_d->SharedPtr();
134 BOOST_CHECK(d == vec_b[0]);
135
136 // Serialize the vector
137 boost::archive::xml_oarchive oa(ss);
138 oa & BOOST_SERIALIZATION_NVP(vec_b);
139 }
140 {
141 // Deserialize it back into a vector of shared_ptr<Base>
142 std::vector<boost::shared_ptr<Base>> vec_b;
143 ss.seekg(0);
144 boost::archive::xml_iarchive ia(ss);
145 ia & BOOST_SERIALIZATION_NVP(vec_b);
146
147 // Get a raw pointer to Derived via shared_ptr<Base>
148 Derived* raw_d = static_cast<Derived*>(vec_b[0].get());
149 // Verify base and derived members
150 BOOST_CHECK(raw_d->m_base==1);
151 BOOST_CHECK(raw_d->m_derived==2);
152
153 // verify shared_from_this
154 // FAIL: The following line throws bad_weak_ptr exception
155 boost::shared_ptr<Derived> d = raw_d->SharedPtr();
156 BOOST_CHECK(d == vec_b[0]);
157 }
158}
159
160BOOST_AUTO_TEST_SUITE_END()