1 //
2 //  sp_array_test.cpp
3 //
4 //  Copyright (c) 2012 Peter Dimov
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt
9 //
10 
11 #include <boost/shared_ptr.hpp>
12 #include <boost/weak_ptr.hpp>
13 #include <boost/enable_shared_from_this.hpp>
14 #include <boost/detail/lightweight_test.hpp>
15 #include <memory>
16 #include <utility>
17 
18 class X: public boost::enable_shared_from_this< X >
19 {
20 public:
21 
22     static int allocations;
23     static int instances;
24 
X()25     X()
26     {
27         ++instances;
28     }
29 
~X()30     ~X()
31     {
32         --instances;
33     }
34 
operator new[](std::size_t n)35     void* operator new[]( std::size_t n )
36     {
37         ++allocations;
38         return ::operator new[]( n );
39     }
40 
operator delete[](void * p)41     void operator delete[]( void* p )
42     {
43         --allocations;
44         ::operator delete[]( p );
45     }
46 
47 private:
48 
49     X( X const& );
50     X& operator=( X const& );
51 };
52 
53 int X::allocations = 0;
54 int X::instances = 0;
55 
56 template< class T> class array_deleter
57 {
58 public:
59 
60     static int calls;
61 
operator ()(T * p) const62     void operator()( T * p ) const
63     {
64         ++calls;
65         delete[] p;
66     }
67 
68 private:
69 
70     template< class Y > void operator()( Y * p ) const;
71 };
72 
73 template< class T > int array_deleter< T >::calls = 0;
74 
main()75 int main()
76 {
77     BOOST_TEST( X::allocations == 0 );
78     BOOST_TEST( X::instances == 0 );
79 
80     {
81         boost::shared_ptr<X[]> px;
82         BOOST_TEST( !px );
83 
84         BOOST_TEST( X::allocations == 0 );
85         BOOST_TEST( X::instances == 0 );
86 
87         boost::shared_ptr<X[]> px2( new X[ 3 ] );
88         BOOST_TEST( px2 );
89 
90         try
91         {
92             px2[0].shared_from_this();
93             BOOST_ERROR( "px2[0].shared_from_this() failed to throw" );
94         }
95         catch( boost::bad_weak_ptr const& )
96         {
97         }
98         catch( ... )
99         {
100             BOOST_ERROR( "px2[0].shared_from_this() threw something else than bad_weak_ptr" );
101         }
102 
103         BOOST_TEST( X::allocations == 1 );
104         BOOST_TEST( X::instances == 3 );
105 
106         {
107             X & rx = px2[ 0 ];
108             BOOST_TEST( &rx == px2.get() );
109         }
110 
111         boost::shared_ptr<X const[]> px3( px2 );
112         BOOST_TEST( px3 == px2 );
113         BOOST_TEST( !( px2 < px3 ) && !( px3 < px2 ) );
114 
115         {
116             X const & rx = px3[ 1 ];
117             BOOST_TEST( &rx == px3.get() + 1 );
118         }
119 
120         px3.reset();
121         px3 = px2;
122         BOOST_TEST( px3 == px2 );
123         BOOST_TEST( !( px2 < px3 ) && !( px3 < px2 ) );
124 
125         boost::shared_ptr<X volatile[]> px4( px2 );
126         BOOST_TEST( px4 == px2 );
127         BOOST_TEST( !( px2 < px4 ) && !( px4 < px2 ) );
128 
129         {
130             X volatile & rx = px4[ 2 ];
131             BOOST_TEST( &rx == px4.get() + 2 );
132         }
133 
134         px4.reset();
135         px4 = px2;
136         BOOST_TEST( px4 == px2 );
137         BOOST_TEST( !( px2 < px4 ) && !( px4 < px2 ) );
138 
139         boost::shared_ptr<void> px5( px2 );
140         BOOST_TEST( px5 == px2 );
141         BOOST_TEST( !( px2 < px5 ) && !( px5 < px2 ) );
142 
143         px5.reset();
144         px5 = px2;
145         BOOST_TEST( px5 == px2 );
146         BOOST_TEST( !( px2 < px5 ) && !( px5 < px2 ) );
147 
148         boost::weak_ptr<X[]> wp( px );
149         BOOST_TEST( wp.lock() == px );
150 
151         boost::weak_ptr<X[]> wp2( px2 );
152         BOOST_TEST( wp2.lock() == px2 );
153 
154         wp2.reset();
155         wp2 = px2;
156         BOOST_TEST( wp2.lock() == px2 );
157 
158         boost::weak_ptr<X const[]> wp3( px2 );
159         BOOST_TEST( wp3.lock() == px2 );
160 
161         wp3.reset();
162         wp3 = px2;
163         BOOST_TEST( wp3.lock() == px2 );
164 
165         boost::weak_ptr<X volatile[]> wp4( px2 );
166         BOOST_TEST( wp4.lock() == px2 );
167 
168         wp4.reset();
169         wp4 = px2;
170         BOOST_TEST( wp4.lock() == px2 );
171 
172         boost::weak_ptr<void> wp5( px2 );
173         BOOST_TEST( wp5.lock() == px2 );
174 
175         wp5.reset();
176         wp5 = px2;
177         BOOST_TEST( wp5.lock() == px2 );
178 
179         px2.reset();
180 
181         BOOST_TEST( X::allocations == 1 );
182         BOOST_TEST( X::instances == 3 );
183 
184         px3.reset();
185         px4.reset();
186         px5.reset();
187 
188         BOOST_TEST( X::allocations == 0 );
189         BOOST_TEST( X::instances == 0 );
190 
191         BOOST_TEST( wp2.lock() == 0 );
192         BOOST_TEST( wp3.lock() == 0 );
193         BOOST_TEST( wp4.lock() == 0 );
194         BOOST_TEST( wp5.lock() == 0 );
195     }
196 
197 #if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
198 
199     {
200         std::unique_ptr<X[]> px( new X[ 4 ] );
201         BOOST_TEST( X::allocations == 1 );
202         BOOST_TEST( X::instances == 4 );
203 
204         boost::shared_ptr<X[]> px2( std::move( px ) );
205         BOOST_TEST( X::allocations == 1 );
206         BOOST_TEST( X::instances == 4 );
207         BOOST_TEST( px.get() == 0 );
208 
209         try
210         {
211             px2[0].shared_from_this();
212             BOOST_ERROR( "px2[0].shared_from_this() failed to throw" );
213         }
214         catch( boost::bad_weak_ptr const& )
215         {
216         }
217         catch( ... )
218         {
219             BOOST_ERROR( "px2[0].shared_from_this() threw something else than bad_weak_ptr" );
220         }
221 
222         px2.reset();
223 
224         BOOST_TEST( X::allocations == 0 );
225         BOOST_TEST( X::instances == 0 );
226     }
227 
228     {
229         std::unique_ptr<X[]> px( new X[ 4 ] );
230         BOOST_TEST( X::allocations == 1 );
231         BOOST_TEST( X::instances == 4 );
232 
233         boost::shared_ptr<X[]> px2;
234         px2 = std::move( px );
235         BOOST_TEST( X::allocations == 1 );
236         BOOST_TEST( X::instances == 4 );
237         BOOST_TEST( px.get() == 0 );
238 
239         try
240         {
241             px2[0].shared_from_this();
242             BOOST_ERROR( "px2[0].shared_from_this() failed to throw" );
243         }
244         catch( boost::bad_weak_ptr const& )
245         {
246         }
247         catch( ... )
248         {
249             BOOST_ERROR( "px2[0].shared_from_this() threw something else than bad_weak_ptr" );
250         }
251 
252         px2.reset();
253 
254         BOOST_TEST( X::allocations == 0 );
255         BOOST_TEST( X::instances == 0 );
256     }
257 
258 #endif
259 
260     {
261         boost::shared_ptr<X[]> px( new X[ 5 ], array_deleter< X >() );
262         BOOST_TEST( X::allocations == 1 );
263         BOOST_TEST( X::instances == 5 );
264 
265         try
266         {
267             px[0].shared_from_this();
268             BOOST_ERROR( "px[0].shared_from_this() failed to throw" );
269         }
270         catch( boost::bad_weak_ptr const& )
271         {
272         }
273         catch( ... )
274         {
275             BOOST_ERROR( "px[0].shared_from_this() threw something else than bad_weak_ptr" );
276         }
277 
278         px.reset();
279 
280         BOOST_TEST( X::allocations == 0 );
281         BOOST_TEST( X::instances == 0 );
282         BOOST_TEST( array_deleter< X >::calls == 1 );
283     }
284 
285     {
286         boost::shared_ptr<X[]> px( new X[ 6 ], array_deleter< X >(), std::allocator< X >() );
287         BOOST_TEST( X::allocations == 1 );
288         BOOST_TEST( X::instances == 6 );
289 
290         try
291         {
292             px[0].shared_from_this();
293             BOOST_ERROR( "px[0].shared_from_this() failed to throw" );
294         }
295         catch( boost::bad_weak_ptr const& )
296         {
297         }
298         catch( ... )
299         {
300             BOOST_ERROR( "px[0].shared_from_this() threw something else than bad_weak_ptr" );
301         }
302 
303         px.reset();
304 
305         BOOST_TEST( X::allocations == 0 );
306         BOOST_TEST( X::instances == 0 );
307         BOOST_TEST( array_deleter< X >::calls == 2 );
308     }
309 
310     return boost::report_errors();
311 }
312