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