Ticket #9567: test_shared_from_this.2.cpp

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

Added test case to demonstrate workaround

Line 
1// This demonstrates a problem with boost::serialization and boost::enable_shared_from_this.
2// (boost version 1.53)
3// See boost TRAC ticket #9567
4//
5// Given the following class structure:
6// Base is a simple class
7// Derived inherits from Base
8// Derived also inherits from boost::enable_shared_from_this<Derived>
9// Base and Derived implement boost::serialization
10//
11// When deserializing an instance of Derived into a vector of boost::shared_ptr<Derived>:
12// Base and Derived members are reconstructed correctly.
13// Derived::shared_from_this() works as expected.
14//
15// But when deserializing an instance of Derived into a vector of boost::shared_ptr<Base>:
16// Base and Derived members are still reconstructed correctly.
17// Derived::shared_from_this() throws a bad_weak_ptr exception.
18// This is because enable_shared_from_this::weak_ptr is NOT reconstructed - It is zero.
19#define BOOST_TEST_MAIN
20#include <boost/test/unit_test.hpp>
21#include <boost/test/output_test_stream.hpp>
22#include <vector>
23#include <boost/shared_ptr.hpp>
24#include <boost/enable_shared_from_this.hpp>
25#include <boost/serialization/shared_ptr.hpp>
26#include <boost/archive/xml_oarchive.hpp>
27#include <boost/archive/xml_iarchive.hpp>
28#include <boost/serialization/vector.hpp>
29#include <boost/serialization/export.hpp>
30
31class Base {
32public:
33 Base() {}
34 virtual ~Base() {} // "virtual" forces RTTI, to enable serialization of Derived from Base pointer
35 int m_base;
36
37 template<class Archive>
38 void serialize(Archive & ar, const unsigned int version)
39 {
40 ar & BOOST_SERIALIZATION_NVP(m_base);
41 }
42};
43
44class Derived : public Base, public boost::enable_shared_from_this<Derived> {
45public:
46 Derived() {}
47 ~Derived() {}
48 boost::shared_ptr<Derived> SharedPtr() { return shared_from_this(); }
49 int m_derived;
50
51 template<class Archive>
52 void serialize(Archive & ar, const unsigned int version)
53 {
54 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
55 ar & BOOST_SERIALIZATION_NVP(m_derived);
56 }
57};
58// The following is required to enable serialization from Base pointer
59BOOST_CLASS_EXPORT(Derived)
60
61BOOST_AUTO_TEST_SUITE(test_shared_from_this)
62
63// This test passes
64BOOST_AUTO_TEST_CASE(deserialize_pointer_Derived)
65{
66 std::stringstream ss;
67
68 {
69 // Create a vector of shared_ptr<Derived> containing an instance of shared_ptr<Derived>
70 std::vector<boost::shared_ptr<Derived>> vec_d;
71 boost::shared_ptr<Derived> d(new Derived());
72 d->m_base = 1;
73 d->m_derived = 2;
74 vec_d.push_back(d);
75 d.reset();
76
77 // Get a raw pointer to Derived
78 Derived* raw_d = vec_d[0].get();
79
80 // Verify base and derived members
81 BOOST_CHECK(raw_d->m_base==1);
82 BOOST_CHECK(raw_d->m_derived==2);
83
84 // verify shared_from_this
85 d = raw_d->SharedPtr();
86 BOOST_CHECK(d == vec_d[0]);
87
88 // Serialize the vector
89 boost::archive::xml_oarchive oa(ss);
90 oa & BOOST_SERIALIZATION_NVP(vec_d);
91 }
92 {
93 // Deserialize it back into a vector of shared_ptr<Derived>
94 std::vector<boost::shared_ptr<Derived>> vec_d;
95 ss.seekg(0);
96 boost::archive::xml_iarchive ia(ss);
97 ia & BOOST_SERIALIZATION_NVP(vec_d);
98
99 // Get a raw pointer to Derived
100 Derived* raw_d = vec_d[0].get();
101
102 // Verify base and derived members
103 BOOST_CHECK(raw_d->m_base==1);
104 BOOST_CHECK(raw_d->m_derived==2);
105
106 // verify shared_from_this
107 boost::shared_ptr<Derived> d = raw_d->SharedPtr();
108 BOOST_CHECK(d == vec_d[0]);
109 }
110}
111
112// This test fails
113BOOST_AUTO_TEST_CASE(deserialize_vector_Base)
114{
115 std::stringstream ss;
116
117 {
118 // Create a vector of shared_ptr<Base> containing an instance of shared_ptr<Derived>
119 std::vector<boost::shared_ptr<Base>> vec_b;
120 boost::shared_ptr<Base> b(new Derived());
121 Derived* raw_d1 = static_cast<Derived*>(b.get());
122 raw_d1->m_base = 1;
123 raw_d1->m_derived = 2;
124 vec_b.push_back(b);
125
126 // Get a raw pointer to Derived via shared_ptr<Base>
127 Derived* raw_d = static_cast<Derived*>(vec_b[0].get());
128
129 // Verify base and derived members
130 BOOST_CHECK(raw_d->m_base==1);
131 BOOST_CHECK(raw_d->m_derived==2);
132
133 // verify shared_from_this
134 boost::shared_ptr<Derived> d = raw_d->SharedPtr();
135 BOOST_CHECK(d == vec_b[0]);
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
160// This test demonstrates a workaround by reconstructing the weak_ptr after deserialization
161BOOST_AUTO_TEST_CASE(deserialize_vector_Base_workaround)
162{
163 std::stringstream ss;
164
165 {
166 // Create a vector of shared_ptr<Base> containing an instance of shared_ptr<Derived>
167 std::vector<boost::shared_ptr<Base>> vec_b;
168 boost::shared_ptr<Base> b(new Derived());
169 Derived* raw_d1 = static_cast<Derived*>(b.get());
170 raw_d1->m_base = 1;
171 raw_d1->m_derived = 2;
172 vec_b.push_back(b);
173
174 // Get a raw pointer to Derived via shared_ptr<Base>
175 Derived* raw_d = static_cast<Derived*>(vec_b[0].get());
176
177 // Verify base and derived members
178 BOOST_CHECK(raw_d->m_base==1);
179 BOOST_CHECK(raw_d->m_derived==2);
180
181 // verify shared_from_this
182 boost::shared_ptr<Derived> d = raw_d->SharedPtr();
183 BOOST_CHECK(d == vec_b[0]);
184 // Serialize the vector
185 boost::archive::xml_oarchive oa(ss);
186 oa & BOOST_SERIALIZATION_NVP(vec_b);
187 }
188 {
189 // Deserialize it back into a vector of shared_ptr<Base>
190 std::vector<boost::shared_ptr<Base>> vec_b;
191 ss.seekg(0);
192 boost::archive::xml_iarchive ia(ss);
193 ia & BOOST_SERIALIZATION_NVP(vec_b);
194
195 // Get a raw pointer to Derived via shared_ptr<Base>
196 Derived* raw_d = static_cast<Derived*>(vec_b[0].get());
197 // Verify base and derived members
198 BOOST_CHECK(raw_d->m_base==1);
199 BOOST_CHECK(raw_d->m_derived==2);
200
201 // WORKAROUND: reconstruct enable_shared_from_this weak_ptr
202 raw_d->_internal_accept_owner(&vec_b[0], raw_d);
203
204 // verify shared_from_this
205 boost::shared_ptr<Derived> d = raw_d->SharedPtr();
206 BOOST_CHECK(d == vec_b[0]);
207 }
208}
209BOOST_AUTO_TEST_SUITE_END()