1 | /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 |
2 | // test_shared_ptr_multi_base.cpp |
3 | |
4 | // (C) Copyright 2002 Robert Ramey- http://www.rrsd.com and Takatoshi Kondo. |
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 | // See http://www.boost.org for updates, documentation, and revision history. |
10 | |
11 | #include <cstddef> // NULL |
12 | #include <cstdio> // remove |
13 | #include <fstream> |
14 | |
15 | #include <boost/config.hpp> |
16 | #if defined(BOOST_NO_STDC_NAMESPACE) |
17 | namespace std{ |
18 | using ::remove; |
19 | } |
20 | #endif |
21 | |
22 | #include <boost/serialization/nvp.hpp> |
23 | #include <boost/serialization/export.hpp> |
24 | |
25 | #include <boost/serialization/shared_ptr.hpp> |
26 | #include <boost/serialization/weak_ptr.hpp> |
27 | |
28 | #include "test_tools.hpp" |
29 | |
30 | struct Base1 { |
31 | Base1() {} |
32 | Base1(int x) : m_x(1 + x) {} |
33 | virtual ~Base1(){ |
34 | } |
35 | int m_x; |
36 | // serialize |
37 | friend class boost::serialization::access; |
38 | template<class Archive> |
39 | void serialize(Archive &ar, const unsigned int /* file_version */) |
40 | { |
41 | ar & BOOST_SERIALIZATION_NVP(m_x); |
42 | } |
43 | }; |
44 | |
45 | struct Base2 { |
46 | Base2() {} |
47 | Base2(int x) : m_x(2 + x) {} |
48 | int m_x; |
49 | virtual ~Base2(){ |
50 | } |
51 | // serialize |
52 | friend class boost::serialization::access; |
53 | template<class Archive> |
54 | void serialize(Archive &ar, const unsigned int /* file_version */) |
55 | { |
56 | ar & BOOST_SERIALIZATION_NVP(m_x); |
57 | } |
58 | }; |
59 | |
60 | struct Base3 { |
61 | Base3() {} |
62 | Base3(int x) : m_x(3 + x) {} |
63 | virtual ~Base3(){ |
64 | } |
65 | int m_x; |
66 | // serialize |
67 | friend class boost::serialization::access; |
68 | template<class Archive> |
69 | void serialize(Archive &ar, const unsigned int /* file_version */) |
70 | { |
71 | ar & BOOST_SERIALIZATION_NVP(m_x); |
72 | } |
73 | }; |
74 | |
75 | // Sub is a subclass of Base1, Base1 and Base3. |
76 | struct Sub:public Base1, public Base2, public Base3 { |
77 | static int count; |
78 | Sub() { |
79 | ++count; |
80 | } |
81 | Sub(int x) : |
82 | Base1(x), |
83 | Base2(x), |
84 | m_x(x) |
85 | { |
86 | ++count; |
87 | } |
88 | Sub(const Sub & rhs) : |
89 | m_x(rhs.m_x) |
90 | { |
91 | ++count; |
92 | } |
93 | virtual ~Sub() { |
94 | assert(0 < count); |
95 | --count; |
96 | } |
97 | int m_x; |
98 | // serialize |
99 | friend class boost::serialization::access; |
100 | template<class Archive> |
101 | void serialize(Archive &ar, const unsigned int /* file_version */) |
102 | { |
103 | ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base1); |
104 | ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base2); |
105 | ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base3); |
106 | ar & BOOST_SERIALIZATION_NVP(m_x); |
107 | } |
108 | }; |
109 | |
110 | // Sub needs to be exported because its serialized via a base class pointer |
111 | BOOST_CLASS_EXPORT(Sub) |
112 | BOOST_SERIALIZATION_SHARED_PTR(Sub) |
113 | |
114 | int Sub::count = 0; |
115 | |
116 | template <class FIRST, class SECOND> |
117 | void save2( |
118 | const char * testfile, |
119 | const FIRST& first, |
120 | const SECOND& second |
121 | ){ |
122 | test_ostream os(testfile, TEST_STREAM_FLAGS); |
123 | test_oarchive oa(os, TEST_ARCHIVE_FLAGS); |
124 | oa << BOOST_SERIALIZATION_NVP(first); |
125 | oa << BOOST_SERIALIZATION_NVP(second); |
126 | } |
127 | |
128 | template <class FIRST, class SECOND> |
129 | void load2( |
130 | const char * testfile, |
131 | FIRST& first, |
132 | SECOND& second) |
133 | { |
134 | test_istream is(testfile, TEST_STREAM_FLAGS); |
135 | test_iarchive ia(is, TEST_ARCHIVE_FLAGS); |
136 | ia >> BOOST_SERIALIZATION_NVP(first); |
137 | ia >> BOOST_SERIALIZATION_NVP(second); |
138 | } |
139 | |
140 | // Run tests by serializing two shared_ptrs into an archive, |
141 | // clearing them (deleting the objects) and then reloading the |
142 | // objects back from an archive. |
143 | |
144 | template<class T, class U> |
145 | boost::shared_ptr<T> dynamic_pointer_cast(boost::shared_ptr<U> const & u) |
146 | BOOST_NOEXCEPT |
147 | { |
148 | return boost::dynamic_pointer_cast<T>(u); |
149 | } |
150 | |
151 | #ifndef BOOST_NO_CXX11_SMART_PTR |
152 | template<class T, class U> |
153 | std::shared_ptr<T> dynamic_pointer_cast(std::shared_ptr<U> const & u) |
154 | BOOST_NOEXCEPT |
155 | { |
156 | return std::dynamic_pointer_cast<T>(u); |
157 | } |
158 | #endif |
159 | |
160 | // Serialization sequence |
161 | // First, shared_ptr |
162 | // Second, weak_ptr |
163 | template <class SP, class WP> |
164 | void shared_weak( |
165 | SP & first, |
166 | WP & second |
167 | ){ |
168 | const char * testfile = boost::archive::tmpnam(NULL); |
169 | BOOST_REQUIRE(NULL != testfile); |
170 | int firstm = first->m_x; |
171 | |
172 | BOOST_REQUIRE(! second.expired()); |
173 | int secondm = second.lock()->m_x; |
174 | save2(testfile, first, second); |
175 | |
176 | // Clear the pointers, thereby destroying the objects they contain |
177 | second.reset(); |
178 | first.reset(); |
179 | |
180 | load2(testfile, first, second); |
181 | BOOST_CHECK(! second.expired()); |
182 | |
183 | // Check data member |
184 | BOOST_CHECK(firstm == first->m_x); |
185 | BOOST_CHECK(secondm == second.lock()->m_x); |
186 | // Check pointer to vtable |
187 | BOOST_CHECK(::dynamic_pointer_cast<Sub>(first)); |
188 | BOOST_CHECK(::dynamic_pointer_cast<Sub>(second.lock())); |
189 | |
190 | std::remove(filename: testfile); |
191 | } |
192 | |
193 | // Serialization sequence |
194 | // First, weak_ptr |
195 | // Second, shared_ptr |
196 | template <class WP, class SP> |
197 | void weak_shared( |
198 | WP & first, |
199 | SP & second |
200 | ){ |
201 | const char * testfile = boost::archive::tmpnam(NULL); |
202 | BOOST_REQUIRE(NULL != testfile); |
203 | BOOST_CHECK(! first.expired()); |
204 | int firstm = first.lock()->m_x; |
205 | int secondm = second->m_x; |
206 | save2(testfile, first, second); |
207 | |
208 | // Clear the pointers, thereby destroying the objects they contain |
209 | first.reset(); |
210 | second.reset(); |
211 | |
212 | load2(testfile, first, second); |
213 | BOOST_CHECK(! first.expired()); |
214 | |
215 | // Check data member |
216 | BOOST_CHECK(firstm == first.lock()->m_x); |
217 | BOOST_CHECK(secondm == second->m_x); |
218 | // Check pointer to vtable |
219 | BOOST_CHECK(::dynamic_pointer_cast<Sub>(first.lock())); |
220 | BOOST_CHECK(::dynamic_pointer_cast<Sub>(second)); |
221 | |
222 | std::remove(filename: testfile); |
223 | } |
224 | |
225 | // This does the tests |
226 | template<template<class T> class SPT, template<class T> class WPT> |
227 | bool test(){ |
228 | // Both Sub |
229 | SPT<Sub> tc1_sp(new Sub(10)); |
230 | WPT<Sub> tc1_wp(tc1_sp); |
231 | shared_weak(tc1_sp, tc1_wp); |
232 | weak_shared(tc1_wp, tc1_sp); |
233 | tc1_sp.reset(); |
234 | BOOST_CHECK(0 == Sub::count); |
235 | |
236 | // Sub and Base1 |
237 | SPT<Sub> tc2_sp(new Sub(10)); |
238 | WPT<Base1> tc2_wp(tc2_sp); |
239 | shared_weak(tc2_sp, tc2_wp); |
240 | weak_shared(tc2_wp, tc2_sp); |
241 | tc2_sp.reset(); |
242 | BOOST_CHECK(0 == Sub::count); |
243 | |
244 | // Sub and Base2 |
245 | SPT<Sub> tc3_sp(new Sub(10)); |
246 | WPT<Base2> tc3_wp(tc3_sp); |
247 | shared_weak(tc3_sp, tc3_wp); |
248 | weak_shared(tc3_wp, tc3_sp); |
249 | tc3_sp.reset(); |
250 | BOOST_CHECK(0 == Sub::count); |
251 | |
252 | // Sub and Base3 |
253 | SPT<Sub> tc4_sp(new Sub(10)); |
254 | WPT<Base3> tc4_wp(tc4_sp); |
255 | shared_weak(tc4_sp, tc4_wp); |
256 | weak_shared(tc4_wp, tc4_sp); |
257 | tc4_sp.reset(); |
258 | BOOST_CHECK(0 == Sub::count); |
259 | |
260 | // Base1 and Base2 |
261 | SPT<Sub> tc5_sp_tmp(new Sub(10)); |
262 | SPT<Base1> tc5_sp(tc5_sp_tmp); |
263 | WPT<Base2> tc5_wp(tc5_sp_tmp); |
264 | tc5_sp_tmp.reset(); |
265 | shared_weak(tc5_sp, tc5_wp); |
266 | weak_shared(tc5_wp, tc5_sp); |
267 | tc5_sp.reset(); |
268 | BOOST_CHECK(0 == Sub::count); |
269 | |
270 | // Base2 and Base3 |
271 | SPT<Sub> tc6_sp_tmp(new Sub(10)); |
272 | SPT<Base2> tc6_sp(tc6_sp_tmp); |
273 | WPT<Base3> tc6_wp(tc6_sp_tmp); |
274 | tc6_sp_tmp.reset(); |
275 | shared_weak(tc6_sp, tc6_wp); |
276 | weak_shared(tc6_wp, tc6_sp); |
277 | tc6_sp.reset(); |
278 | BOOST_CHECK(0 == Sub::count); |
279 | |
280 | // Base3 and Base1 |
281 | SPT<Sub> tc7_sp_tmp(new Sub(10)); |
282 | SPT<Base3> tc7_sp(tc7_sp_tmp); |
283 | WPT<Base1> tc7_wp(tc7_sp_tmp); |
284 | tc7_sp_tmp.reset(); |
285 | shared_weak(tc7_sp, tc7_wp); |
286 | weak_shared(tc7_wp, tc7_sp); |
287 | tc7_sp.reset(); |
288 | BOOST_CHECK(0 == Sub::count); |
289 | |
290 | return true; |
291 | } |
292 | |
293 | // This does the tests |
294 | int test_main(int /* argc */, char * /* argv */[]) |
295 | { |
296 | bool result = true; |
297 | result &= test<boost::shared_ptr, boost::weak_ptr>(); |
298 | #ifndef BOOST_NO_CXX11_SMART_PTR |
299 | result &= test<std::shared_ptr, std::weak_ptr>(); |
300 | #endif |
301 | return result ? EXIT_SUCCESS : EXIT_FAILURE; |
302 | } |
303 | |