1 | #include <boost/config.hpp> |
2 | |
3 | #if defined(BOOST_MSVC) |
4 | |
5 | #pragma warning(disable: 4786) // identifier truncated in debug info |
6 | #pragma warning(disable: 4710) // function not inlined |
7 | #pragma warning(disable: 4711) // function selected for automatic inline expansion |
8 | #pragma warning(disable: 4514) // unreferenced inline removed |
9 | #pragma warning(disable: 4355) // 'this' : used in base member initializer list |
10 | |
11 | #if (BOOST_MSVC >= 1310) |
12 | #pragma warning(disable: 4675) // resolved overload found with Koenig lookup |
13 | #endif |
14 | |
15 | #endif |
16 | |
17 | #if defined(__GNUC__) && __GNUC__ > 4 |
18 | # pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" |
19 | #endif |
20 | |
21 | // |
22 | // shared_ptr_basic_test.cpp |
23 | // |
24 | // Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. |
25 | // |
26 | // Distributed under the Boost Software License, Version 1.0. (See |
27 | // accompanying file LICENSE_1_0.txt or copy at |
28 | // http://www.boost.org/LICENSE_1_0.txt) |
29 | // |
30 | |
31 | #include <boost/core/lightweight_test.hpp> |
32 | |
33 | #include <boost/shared_ptr.hpp> |
34 | #include <boost/weak_ptr.hpp> |
35 | |
36 | int cnt = 0; |
37 | |
38 | struct X |
39 | { |
40 | X() |
41 | { |
42 | ++cnt; |
43 | } |
44 | |
45 | ~X() // virtual destructor deliberately omitted |
46 | { |
47 | --cnt; |
48 | } |
49 | |
50 | virtual int id() const |
51 | { |
52 | return 1; |
53 | } |
54 | |
55 | private: |
56 | |
57 | X(X const &); |
58 | X & operator= (X const &); |
59 | }; |
60 | |
61 | struct Y: public X |
62 | { |
63 | Y() |
64 | { |
65 | ++cnt; |
66 | } |
67 | |
68 | ~Y() |
69 | { |
70 | --cnt; |
71 | } |
72 | |
73 | virtual int id() const |
74 | { |
75 | return 2; |
76 | } |
77 | |
78 | private: |
79 | |
80 | Y(Y const &); |
81 | Y & operator= (Y const &); |
82 | }; |
83 | |
84 | int * get_object() |
85 | { |
86 | ++cnt; |
87 | return &cnt; |
88 | } |
89 | |
90 | void release_object(int * p) |
91 | { |
92 | BOOST_TEST(p == &cnt); |
93 | --cnt; |
94 | } |
95 | |
96 | template<class T> void test_is_X(boost::shared_ptr<T> const & p) |
97 | { |
98 | BOOST_TEST(p->id() == 1); |
99 | BOOST_TEST((*p).id() == 1); |
100 | } |
101 | |
102 | template<class T> void test_is_X(boost::weak_ptr<T> const & p) |
103 | { |
104 | BOOST_TEST(p.get() != 0); |
105 | BOOST_TEST(p.get()->id() == 1); |
106 | } |
107 | |
108 | template<class T> void test_is_Y(boost::shared_ptr<T> const & p) |
109 | { |
110 | BOOST_TEST(p->id() == 2); |
111 | BOOST_TEST((*p).id() == 2); |
112 | } |
113 | |
114 | template<class T> void test_is_Y(boost::weak_ptr<T> const & p) |
115 | { |
116 | boost::shared_ptr<T> q = p.lock(); |
117 | BOOST_TEST(q.get() != 0); |
118 | BOOST_TEST(q->id() == 2); |
119 | } |
120 | |
121 | template<class T> void test_eq(T const & a, T const & b) |
122 | { |
123 | BOOST_TEST(a == b); |
124 | BOOST_TEST(!(a != b)); |
125 | BOOST_TEST(!(a < b)); |
126 | BOOST_TEST(!(b < a)); |
127 | } |
128 | |
129 | template<class T> void test_ne(T const & a, T const & b) |
130 | { |
131 | BOOST_TEST(!(a == b)); |
132 | BOOST_TEST(a != b); |
133 | BOOST_TEST(a < b || b < a); |
134 | BOOST_TEST(!(a < b && b < a)); |
135 | } |
136 | |
137 | template<class T, class U> void test_shared(boost::weak_ptr<T> const & a, boost::weak_ptr<U> const & b) |
138 | { |
139 | BOOST_TEST(!(a < b)); |
140 | BOOST_TEST(!(b < a)); |
141 | } |
142 | |
143 | template<class T, class U> void test_nonshared(boost::weak_ptr<T> const & a, boost::weak_ptr<U> const & b) |
144 | { |
145 | BOOST_TEST(a < b || b < a); |
146 | BOOST_TEST(!(a < b && b < a)); |
147 | } |
148 | |
149 | template<class T, class U> void test_eq2(T const & a, U const & b) |
150 | { |
151 | BOOST_TEST(a == b); |
152 | BOOST_TEST(!(a != b)); |
153 | } |
154 | |
155 | template<class T, class U> void test_ne2(T const & a, U const & b) |
156 | { |
157 | BOOST_TEST(!(a == b)); |
158 | BOOST_TEST(a != b); |
159 | } |
160 | |
161 | template<class T> void test_is_zero(boost::shared_ptr<T> const & p) |
162 | { |
163 | BOOST_TEST(!p); |
164 | BOOST_TEST(p.get() == 0); |
165 | } |
166 | |
167 | template<class T> void test_is_nonzero(boost::shared_ptr<T> const & p) |
168 | { |
169 | // p? true: false is used to test p in a boolean context. |
170 | // BOOST_TEST(p) is not guaranteed to test the conversion, |
171 | // as the macro might test !!p instead. |
172 | BOOST_TEST(p? true: false); |
173 | BOOST_TEST(p.get() != 0); |
174 | } |
175 | |
176 | int main() |
177 | { |
178 | using namespace boost; |
179 | |
180 | { |
181 | shared_ptr<X> p(new Y); |
182 | shared_ptr<X> p2(new X); |
183 | |
184 | test_is_nonzero(p); |
185 | test_is_nonzero(p: p2); |
186 | test_is_Y(p); |
187 | test_is_X(p: p2); |
188 | test_ne(a: p, b: p2); |
189 | |
190 | { |
191 | shared_ptr<X> q(p); |
192 | test_eq(a: p, b: q); |
193 | } |
194 | |
195 | #if !defined( BOOST_NO_RTTI ) |
196 | shared_ptr<Y> p3 = dynamic_pointer_cast<Y>(r: p); |
197 | shared_ptr<Y> p4 = dynamic_pointer_cast<Y>(r: p2); |
198 | |
199 | test_is_nonzero(p: p3); |
200 | test_is_zero(p: p4); |
201 | |
202 | BOOST_TEST(p.use_count() == 2); |
203 | BOOST_TEST(p2.use_count() == 1); |
204 | BOOST_TEST(p3.use_count() == 2); |
205 | |
206 | test_is_Y(p: p3); |
207 | test_eq2(a: p, b: p3); |
208 | test_ne2(a: p2, b: p4); |
209 | #endif |
210 | |
211 | shared_ptr<void> p5(p); |
212 | |
213 | test_is_nonzero(p: p5); |
214 | test_eq2(a: p, b: p5); |
215 | |
216 | weak_ptr<X> wp1(p2); |
217 | |
218 | BOOST_TEST(!wp1.expired()); |
219 | BOOST_TEST(wp1.use_count() != 0); |
220 | |
221 | p.reset(); |
222 | p2.reset(); |
223 | #if !defined( BOOST_NO_RTTI ) |
224 | p3.reset(); |
225 | p4.reset(); |
226 | #endif |
227 | |
228 | test_is_zero(p); |
229 | test_is_zero(p: p2); |
230 | #if !defined( BOOST_NO_RTTI ) |
231 | test_is_zero(p: p3); |
232 | test_is_zero(p: p4); |
233 | #endif |
234 | |
235 | BOOST_TEST(p5.use_count() == 1); |
236 | |
237 | BOOST_TEST(wp1.expired()); |
238 | BOOST_TEST(wp1.use_count() == 0); |
239 | |
240 | try |
241 | { |
242 | shared_ptr<X> sp1(wp1); |
243 | BOOST_ERROR("shared_ptr<X> sp1(wp1) failed to throw" ); |
244 | } |
245 | catch(boost::bad_weak_ptr const &) |
246 | { |
247 | } |
248 | |
249 | test_is_zero(p: wp1.lock()); |
250 | |
251 | weak_ptr<X> wp2 = static_pointer_cast<X>(r: p5); |
252 | |
253 | BOOST_TEST(wp2.use_count() == 1); |
254 | test_is_Y(p: wp2); |
255 | test_nonshared(a: wp1, b: wp2); |
256 | |
257 | // Scoped to not affect the subsequent use_count() tests. |
258 | { |
259 | shared_ptr<X> sp2(wp2); |
260 | test_is_nonzero(p: wp2.lock()); |
261 | } |
262 | |
263 | #if !defined( BOOST_NO_RTTI ) |
264 | weak_ptr<Y> wp3 = dynamic_pointer_cast<Y>(r: wp2.lock()); |
265 | |
266 | BOOST_TEST(wp3.use_count() == 1); |
267 | test_shared(a: wp2, b: wp3); |
268 | |
269 | weak_ptr<X> wp4(wp3); |
270 | |
271 | BOOST_TEST(wp4.use_count() == 1); |
272 | test_shared(a: wp2, b: wp4); |
273 | #endif |
274 | |
275 | wp1 = p2; |
276 | test_is_zero(p: wp1.lock()); |
277 | |
278 | #if !defined( BOOST_NO_RTTI ) |
279 | wp1 = p4; |
280 | wp1 = wp3; |
281 | #endif |
282 | wp1 = wp2; |
283 | |
284 | BOOST_TEST(wp1.use_count() == 1); |
285 | test_shared(a: wp1, b: wp2); |
286 | |
287 | weak_ptr<X> wp5; |
288 | |
289 | bool b1 = wp1 < wp5; |
290 | bool b2 = wp5 < wp1; |
291 | |
292 | p5.reset(); |
293 | |
294 | BOOST_TEST(wp1.use_count() == 0); |
295 | BOOST_TEST(wp2.use_count() == 0); |
296 | #if !defined( BOOST_NO_RTTI ) |
297 | BOOST_TEST(wp3.use_count() == 0); |
298 | #endif |
299 | |
300 | // Test operator< stability for std::set< weak_ptr<> > |
301 | // Thanks to Joe Gottman for pointing this out |
302 | |
303 | BOOST_TEST(b1 == (wp1 < wp5)); |
304 | BOOST_TEST(b2 == (wp5 < wp1)); |
305 | |
306 | { |
307 | // note that both get_object and release_object deal with int* |
308 | shared_ptr<void> p6(get_object(), release_object); |
309 | } |
310 | } |
311 | |
312 | BOOST_TEST(cnt == 0); |
313 | |
314 | return boost::report_errors(); |
315 | } |
316 | |