Ticket #1884: make_shared.hpp

File make_shared.hpp, 7.9 KB (added by Frank Mori Hess, 14 years ago)
Line 
1#ifndef BOOST_MAKE_SHARED_HPP_INCLUDED
2#define BOOST_MAKE_SHARED_HPP_INCLUDED
3
4//
5// make_shared.hpp
6//
7// Copyright (c) 2007 Peter Dimov
8//
9// Distributed under the Boost Software License, Version 1.0. (See
10// accompanying file LICENSE_1_0.txt or copy at
11// http://www.boost.org/LICENSE_1_0.txt)
12//
13// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation.
14//
15
16#include <boost/config.hpp>
17#include <boost/shared_ptr.hpp>
18#include <boost/type_traits/type_with_alignment.hpp>
19#include <boost/type_traits/alignment_of.hpp>
20#include <cstddef>
21#include <new>
22
23namespace boost
24{
25namespace detail
26{
27 template< std::size_t N, std::size_t A > struct sp_aligned_storage
28 {
29 union type
30 {
31 char data_[ N ];
32 typename boost::type_with_alignment< A >::type align_;
33 };
34 };
35
36 template< class T > class sp_ms_deleter
37 {
38 private:
39
40 typedef typename sp_aligned_storage< sizeof( T ), boost::alignment_of< T >::value >::type storage_type;
41
42 bool initialized_;
43 storage_type storage_;
44
45 private:
46
47 void destroy()
48 {
49 if( initialized_ )
50 {
51 reinterpret_cast< T* >( storage_.data_ )->~T();
52 initialized_ = false;
53 }
54 }
55
56 public:
57
58 sp_ms_deleter(): initialized_( false )
59 {
60 }
61
62 ~sp_ms_deleter()
63 {
64 destroy();
65 }
66
67 void operator()( T * )
68 {
69 destroy();
70 }
71
72 void * address()
73 {
74 return storage_.data_;
75 }
76
77 void set_initialized()
78 {
79 initialized_ = true;
80 }
81 };
82} // namespace detail
83
84// Zero-argument versions
85//
86// Used even when variadic templates are available because of the new T() vs new T issue
87
88template< class T > boost::shared_ptr< T > make_shared()
89{
90 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() );
91
92 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
93
94 void * pv = pd->address();
95
96 new( pv ) T();
97 pd->set_initialized();
98
99 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
100}
101
102template< class T, class A > boost::shared_ptr< T > allocate_shared( A const & a )
103{
104 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a );
105
106 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
107
108 void * pv = pd->address();
109
110 new( pv ) T();
111 pd->set_initialized();
112
113 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
114}
115
116// FIXME: boost doesn't seem to have a compiler agnostic replacement for __STRICT_ANSI__
117#if defined( BOOST_HAS_VARIADIC_TMPL ) && defined( BOOST_HAS_RVALUE_REFS ) && !defined( __STRICT_ANSI__ )
118
119// Variadic templates, rvalue reference
120
121template< class T> T forward( T t )
122{
123 return t;
124}
125
126template< class T, class... Args > boost::shared_ptr< T > make_shared( Args && ... args )
127{
128 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() );
129
130 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
131
132 void * pv = pd->address();
133
134 new( pv ) T( forward<Args>( args )... );
135 pd->set_initialized();
136
137 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
138}
139
140template< class T, class A, class... Args > boost::shared_ptr< T > allocate_shared( A const & a, Args && ... args )
141{
142 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a );
143
144 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
145
146 void * pv = pd->address();
147
148 new( pv ) T( forward<Args>( args )... );
149 pd->set_initialized();
150
151 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
152}
153
154#else
155
156// C++03 version
157
158template< class T, class A1 > boost::shared_ptr< T > make_shared( A1 const & a1 )
159{
160 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() );
161
162 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
163
164 void * pv = pd->address();
165
166 new( pv ) T( a1 );
167 pd->set_initialized();
168
169 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
170}
171
172template< class T, class A, class A1 > boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1 )
173{
174 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a );
175
176 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
177
178 void * pv = pd->address();
179
180 new( pv ) T( a1 );
181 pd->set_initialized();
182
183 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
184}
185
186template< class T, class A1, class A2 > boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2 )
187{
188 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() );
189
190 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
191
192 void * pv = pd->address();
193
194 new( pv ) T( a1, a2 );
195 pd->set_initialized();
196
197 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
198}
199
200template< class T, class A, class A1, class A2 > boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a2 )
201{
202 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a );
203
204 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
205
206 void * pv = pd->address();
207
208 new( pv ) T( a1, a2 );
209 pd->set_initialized();
210
211 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
212}
213
214template< class T, class A1, class A2, class A3 > boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3 )
215{
216 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() );
217
218 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
219
220 void * pv = pd->address();
221
222 new( pv ) T( a1, a2, a3 );
223 pd->set_initialized();
224
225 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
226}
227
228template< class T, class A, class A1, class A2, class A3 > boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3 )
229{
230 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a );
231
232 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
233
234 void * pv = pd->address();
235
236 new( pv ) T( a1, a2, a3 );
237 pd->set_initialized();
238
239 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
240}
241
242template< class T, class A1, class A2, class A3, class A4 > boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4 )
243{
244 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() );
245
246 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
247
248 void * pv = pd->address();
249
250 new( pv ) T( a1, a2, a3, a4 );
251 pd->set_initialized();
252
253 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
254}
255
256template< class T, class A, class A1, class A2, class A3, class A4 > boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4 )
257{
258 boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a );
259
260 detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt );
261
262 void * pv = pd->address();
263
264 new( pv ) T( a1, a2, a3, a4 );
265 pd->set_initialized();
266
267 return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) );
268}
269
270#endif
271
272} // namespace boost
273
274#endif // #ifndef BOOST_MAKE_SHARED_HPP_INCLUDED