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 {
Base1Base131     Base1() {}
Base1Base132     Base1(int x) : m_x(1 + x) {}
~Base1Base133     virtual ~Base1(){
34     }
35     int m_x;
36     // serialize
37     friend class boost::serialization::access;
38     template<class Archive>
serializeBase139     void serialize(Archive &ar, const unsigned int /* file_version */)
40     {
41         ar & BOOST_SERIALIZATION_NVP(m_x);
42     }
43 };
44 
45 struct Base2 {
Base2Base246     Base2() {}
Base2Base247     Base2(int x) : m_x(2 + x) {}
48     int m_x;
~Base2Base249     virtual ~Base2(){
50     }
51     // serialize
52     friend class boost::serialization::access;
53     template<class Archive>
serializeBase254     void serialize(Archive &ar, const unsigned int /* file_version */)
55     {
56         ar & BOOST_SERIALIZATION_NVP(m_x);
57     }
58 };
59 
60 struct Base3 {
Base3Base361     Base3() {}
Base3Base362     Base3(int x) : m_x(3 + x) {}
~Base3Base363     virtual ~Base3(){
64     }
65     int m_x;
66     // serialize
67     friend class boost::serialization::access;
68     template<class Archive>
serializeBase369     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;
SubSub78     Sub() {
79         ++count;
80     }
SubSub81     Sub(int x) :
82         Base1(x),
83         Base2(x),
84         m_x(x)
85     {
86         ++count;
87     }
SubSub88     Sub(const Sub & rhs) :
89         m_x(rhs.m_x)
90     {
91         ++count;
92     }
~SubSub93     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>
serializeSub101     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>
save2(const char * testfile,const FIRST & first,const SECOND & 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>
load2(const char * testfile,FIRST & first,SECOND & 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>
dynamic_pointer_cast(boost::shared_ptr<U> const & 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>
dynamic_pointer_cast(std::shared_ptr<U> const & 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>
shared_weak(SP & first,WP & second)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(testfile);
191 }
192 
193 // Serialization sequence
194 // First,  weak_ptr
195 // Second, shared_ptr
196 template <class WP, class SP>
weak_shared(WP & first,SP & second)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(testfile);
223 }
224 
225 // This does the tests
226 template<template<class T> class SPT, template<class T> class WPT>
test()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
test_main(int,char * [])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