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>
serialize(Archive & ar,const unsigned int)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;
operator ==(const A & rhs) const44     bool operator==(const A & rhs) const {
45         return x == rhs.x;
46     }
A()47     A(){++count;}    // default constructor
~A()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>
serialize(Archive & ar,const unsigned int)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;
B()66     B() : A() {};
~B()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>
serialize(Archive & ar,const unsigned int)81     void serialize(Archive & ar, const unsigned int /* file_version */){
82         ar & BOOST_SERIALIZATION_NVP(z);
83     }
84 public:
85     static int count;
operator ==(const C & rhs) const86     bool operator==(const C & rhs) const {
87         return z == rhs.z;
88     }
C()89     C() :
90         z(++count)    // default constructor
91     {}
~C()92     virtual ~C(){--count;}   // default destructor
93 };
94 
95 int C::count = 0;
96 
97 template<class SP>
save(const char * testfile,const SP & spa)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>
load(const char * testfile,SP & spa)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>
save_and_load(SP & spa)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(testfile);
128 }
129 
130 template<class SP>
save2(const char * testfile,const SP & first,const SP & second)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>
load2(const char * testfile,SP & first,SP & second)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>
save_and_load2(SP & first,SP & second)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(testfile);
173 }
174 
175 template<class SP, class WP>
save3(const char * testfile,SP & first,SP & second,WP & third)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>
load3(const char * testfile,SP & first,SP & second,WP & third)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>
save_and_load3(SP & first,SP & second,WP & third)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(testfile);
227 }
228 
229 template<class SP>
save4(const char * testfile,const SP & spc)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>
load4(const char * testfile,SP & spc)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>
save_and_load4(SP & spc)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(testfile);
260 }
261 
262 // This does the tests
263 template<template<class T> class SPT , template<class T> class WPT >
test()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         //trivival 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
test_main(int,char * [])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