1 | /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 |
2 | // test_shared_ptr.cpp |
3 | |
4 | // (C) Copyright 2002 Robert Ramey- http://www.rrsd.com - David Tonge . |
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 | #include <boost/serialization/shared_ptr.hpp> |
25 | #include <boost/serialization/weak_ptr.hpp> |
26 | |
27 | #include "test_tools.hpp" |
28 | |
29 | // This is a simple class. It contains a counter of the number |
30 | // of objects of this class which have been instantiated. |
31 | class A |
32 | { |
33 | private: |
34 | friend class boost::serialization::access; |
35 | int x; |
36 | template<class Archive> |
37 | void serialize(Archive & ar, const unsigned int /* file_version */){ |
38 | ar & BOOST_SERIALIZATION_NVP(x); |
39 | } |
40 | A(A const & rhs); |
41 | A& operator=(A const & rhs); |
42 | public: |
43 | static int count; |
44 | bool operator==(const A & rhs) const { |
45 | return x == rhs.x; |
46 | } |
47 | A(){++count;} // default constructor |
48 | virtual ~A(){--count;} // default destructor |
49 | }; |
50 | |
51 | BOOST_SERIALIZATION_SHARED_PTR(A) |
52 | |
53 | int A::count = 0; |
54 | |
55 | // B is a subclass of A |
56 | class B : public A |
57 | { |
58 | private: |
59 | friend class boost::serialization::access; |
60 | template<class Archive> |
61 | void serialize(Archive & ar, const unsigned int /* file_version */){ |
62 | ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(A); |
63 | } |
64 | public: |
65 | static int count; |
66 | B() : A() {}; |
67 | virtual ~B() {}; |
68 | }; |
69 | |
70 | // B needs to be exported because its serialized via a base class pointer |
71 | BOOST_CLASS_EXPORT(B) |
72 | BOOST_SERIALIZATION_SHARED_PTR(B) |
73 | |
74 | // test a non-polymorphic class |
75 | class C |
76 | { |
77 | private: |
78 | friend class boost::serialization::access; |
79 | int z; |
80 | template<class Archive> |
81 | void serialize(Archive & ar, const unsigned int /* file_version */){ |
82 | ar & BOOST_SERIALIZATION_NVP(z); |
83 | } |
84 | public: |
85 | static int count; |
86 | bool operator==(const C & rhs) const { |
87 | return z == rhs.z; |
88 | } |
89 | C() : |
90 | z(++count) // default constructor |
91 | {} |
92 | virtual ~C(){--count;} // default destructor |
93 | }; |
94 | |
95 | int C::count = 0; |
96 | |
97 | template<class SP> |
98 | void save(const char * testfile, const SP & spa) |
99 | { |
100 | test_ostream os(testfile, TEST_STREAM_FLAGS); |
101 | test_oarchive oa(os, TEST_ARCHIVE_FLAGS); |
102 | oa << BOOST_SERIALIZATION_NVP(spa); |
103 | } |
104 | |
105 | template<class SP> |
106 | void load(const char * testfile, SP & spa) |
107 | { |
108 | test_istream is(testfile, TEST_STREAM_FLAGS); |
109 | test_iarchive ia(is, TEST_ARCHIVE_FLAGS); |
110 | ia >> BOOST_SERIALIZATION_NVP(spa); |
111 | } |
112 | |
113 | // trivial test |
114 | template<class SP> |
115 | void save_and_load(SP & spa) |
116 | { |
117 | const char * testfile = boost::archive::tmpnam(NULL); |
118 | BOOST_REQUIRE(NULL != testfile); |
119 | save(testfile, spa); |
120 | SP spa1; |
121 | load(testfile, spa1); |
122 | |
123 | BOOST_CHECK( |
124 | (spa.get() == NULL && spa1.get() == NULL) |
125 | || * spa == * spa1 |
126 | ); |
127 | std::remove(filename: testfile); |
128 | } |
129 | |
130 | template<class SP> |
131 | void save2( |
132 | const char * testfile, |
133 | const SP & first, |
134 | const SP & second |
135 | ){ |
136 | test_ostream os(testfile, TEST_STREAM_FLAGS); |
137 | test_oarchive oa(os, TEST_ARCHIVE_FLAGS); |
138 | oa << BOOST_SERIALIZATION_NVP(first); |
139 | oa << BOOST_SERIALIZATION_NVP(second); |
140 | } |
141 | |
142 | template<class SP> |
143 | void load2( |
144 | const char * testfile, |
145 | SP & first, |
146 | SP & second) |
147 | { |
148 | test_istream is(testfile, TEST_STREAM_FLAGS); |
149 | test_iarchive ia(is, TEST_ARCHIVE_FLAGS); |
150 | ia >> BOOST_SERIALIZATION_NVP(first); |
151 | ia >> BOOST_SERIALIZATION_NVP(second); |
152 | } |
153 | |
154 | // Run tests by serializing two shared_ptrs into an archive, |
155 | // clearing them (deleting the objects) and then reloading the |
156 | // objects back from an archive. |
157 | template<class SP> |
158 | void save_and_load2(SP & first, SP & second) |
159 | { |
160 | const char * testfile = boost::archive::tmpnam(NULL); |
161 | BOOST_REQUIRE(NULL != testfile); |
162 | |
163 | save2(testfile, first, second); |
164 | |
165 | // Clear the pointers, thereby destroying the objects they contain |
166 | first.reset(); |
167 | second.reset(); |
168 | |
169 | load2(testfile, first, second); |
170 | |
171 | BOOST_CHECK(first == second); |
172 | std::remove(filename: testfile); |
173 | } |
174 | |
175 | template<class SP, class WP> |
176 | void save3( |
177 | const char * testfile, |
178 | SP & first, |
179 | SP & second, |
180 | WP & third |
181 | ){ |
182 | test_ostream os(testfile, TEST_STREAM_FLAGS); |
183 | test_oarchive oa(os, TEST_ARCHIVE_FLAGS); |
184 | oa << BOOST_SERIALIZATION_NVP(third); |
185 | oa << BOOST_SERIALIZATION_NVP(first); |
186 | oa << BOOST_SERIALIZATION_NVP(second); |
187 | } |
188 | |
189 | template<class SP, class WP> |
190 | void load3( |
191 | const char * testfile, |
192 | SP & first, |
193 | SP & second, |
194 | WP & third |
195 | ){ |
196 | test_istream is(testfile, TEST_STREAM_FLAGS); |
197 | test_iarchive ia(is, TEST_ARCHIVE_FLAGS); |
198 | // note that we serialize the weak pointer first |
199 | ia >> BOOST_SERIALIZATION_NVP(third); |
200 | // inorder to test that a temporarily solitary weak pointer |
201 | // correctly restored. |
202 | ia >> BOOST_SERIALIZATION_NVP(first); |
203 | ia >> BOOST_SERIALIZATION_NVP(second); |
204 | } |
205 | |
206 | template<class SP, class WP> |
207 | void save_and_load3( |
208 | SP & first, |
209 | SP & second, |
210 | WP & third |
211 | ){ |
212 | const char * testfile = boost::archive::tmpnam(NULL); |
213 | BOOST_REQUIRE(NULL != testfile); |
214 | |
215 | save3(testfile, first, second, third); |
216 | |
217 | // Clear the pointers, thereby destroying the objects they contain |
218 | first.reset(); |
219 | second.reset(); |
220 | third.reset(); |
221 | |
222 | load3(testfile, first, second, third); |
223 | |
224 | BOOST_CHECK(first == second); |
225 | BOOST_CHECK(first == third.lock()); |
226 | std::remove(filename: testfile); |
227 | } |
228 | |
229 | template<class SP> |
230 | void save4(const char * testfile, const SP & spc) |
231 | { |
232 | test_ostream os(testfile, TEST_STREAM_FLAGS); |
233 | test_oarchive oa(os, TEST_ARCHIVE_FLAGS); |
234 | oa << BOOST_SERIALIZATION_NVP(spc); |
235 | } |
236 | |
237 | template<class SP> |
238 | void load4(const char * testfile, SP & spc) |
239 | { |
240 | test_istream is(testfile, TEST_STREAM_FLAGS); |
241 | test_iarchive ia(is, TEST_ARCHIVE_FLAGS); |
242 | ia >> BOOST_SERIALIZATION_NVP(spc); |
243 | } |
244 | |
245 | // trivial test |
246 | template<class SP> |
247 | void save_and_load4(SP & spc) |
248 | { |
249 | const char * testfile = boost::archive::tmpnam(NULL); |
250 | BOOST_REQUIRE(NULL != testfile); |
251 | save4(testfile, spc); |
252 | SP spc1; |
253 | load4(testfile, spc1); |
254 | |
255 | BOOST_CHECK( |
256 | (spc.get() == NULL && spc1.get() == NULL) |
257 | || * spc == * spc1 |
258 | ); |
259 | std::remove(filename: testfile); |
260 | } |
261 | |
262 | // This does the tests |
263 | template<template<class T> class SPT , template<class T> class WPT > |
264 | bool test(){ |
265 | { |
266 | SPT<A> spa; |
267 | // These are our shared_ptrs |
268 | spa = SPT<A>(new A); |
269 | SPT<A> spa1 = spa; |
270 | spa1 = spa; |
271 | } |
272 | { |
273 | // These are our shared_ptrs |
274 | SPT<A> spa; |
275 | |
276 | // trivial test 1 |
277 | save_and_load(spa); |
278 | |
279 | // trivial test 2 |
280 | spa = SPT<A>(new A); |
281 | save_and_load(spa); |
282 | |
283 | // Try to save and load pointers to As |
284 | spa = SPT<A>(new A); |
285 | SPT<A> spa1 = spa; |
286 | save_and_load2(spa, spa1); |
287 | |
288 | // Try to save and load pointers to Bs |
289 | spa = SPT<A>(new B); |
290 | spa1 = spa; |
291 | save_and_load2(spa, spa1); |
292 | |
293 | // test a weak pointer |
294 | spa = SPT<A>(new A); |
295 | spa1 = spa; |
296 | WPT<A> wp = spa; |
297 | save_and_load3(spa, spa1, wp); |
298 | |
299 | // obj of type B gets destroyed |
300 | // as smart_ptr goes out of scope |
301 | } |
302 | BOOST_CHECK(A::count == 0); |
303 | { |
304 | // Try to save and load pointers to Cs |
305 | SPT<C> spc; |
306 | spc = SPT<C>(new C); |
307 | save_and_load4(spc); |
308 | } |
309 | BOOST_CHECK(C::count == 0); |
310 | return true; |
311 | } |
312 | // This does the tests |
313 | int test_main(int /* argc */, char * /* argv */[]) |
314 | { |
315 | bool result = true; |
316 | result &= test<boost::shared_ptr, boost::weak_ptr>(); |
317 | #ifndef BOOST_NO_CXX11_SMART_PTR |
318 | result &= test<std::shared_ptr, std::weak_ptr>(); |
319 | #endif |
320 | return result ? EXIT_SUCCESS : EXIT_FAILURE; |
321 | } |
322 | |
323 | |