1 //////////////////////////////////////////////////////////////////////////////
3 // This file is the adaptation for Interprocess of boost/shared_ptr.hpp
5 // (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
6 // (C) Copyright Peter Dimov 2001, 2002, 2003
7 // (C) Copyright Ion Gaztanaga 2006-2012.
8 // Distributed under the Boost Software License, Version 1.0.
9 // (See accompanying file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt)
12 // See http://www.boost.org/libs/interprocess for documentation.
14 //////////////////////////////////////////////////////////////////////////////
16 #ifndef BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED
17 #define BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED
19 #ifndef BOOST_CONFIG_HPP
20 # include <boost/config.hpp>
23 #if defined(BOOST_HAS_PRAGMA_ONCE)
27 #include <boost/interprocess/detail/config_begin.hpp>
28 #include <boost/interprocess/detail/workaround.hpp>
30 #include <boost/interprocess/detail/utilities.hpp>
31 #include <boost/interprocess/detail/cast_tags.hpp>
32 #include <boost/assert.hpp>
33 #include <boost/interprocess/smart_ptr/detail/shared_count.hpp>
34 #include <boost/interprocess/detail/mpl.hpp>
35 #include <boost/interprocess/detail/nothrow.hpp>
36 #include <boost/move/utility_core.hpp>
37 #include <boost/interprocess/detail/type_traits.hpp>
38 #include <boost/interprocess/allocators/allocator.hpp>
39 #include <boost/interprocess/smart_ptr/deleter.hpp>
40 #include <boost/static_assert.hpp>
41 #include <boost/intrusive/pointer_traits.hpp>
43 #include <iosfwd> // for std::basic_ostream
46 //!Describes the smart pointer shared_ptr
49 namespace interprocess{
51 template<class T, class VoidAllocator, class Deleter> class weak_ptr;
52 template<class T, class VoidAllocator, class Deleter> class enable_shared_from_this;
56 template<class T, class VoidAllocator, class Deleter>
57 inline void sp_enable_shared_from_this
58 (shared_count<T, VoidAllocator, Deleter> const & pn
59 ,enable_shared_from_this<T, VoidAllocator, Deleter> *pe
65 pe->_internal_weak_this._internal_assign(pn);
69 template<class T, class VoidAllocator, class Deleter>
70 inline void sp_enable_shared_from_this(shared_count<T, VoidAllocator, Deleter> const &, ...)
73 } // namespace ipcdetail
75 //!shared_ptr stores a pointer to a dynamically allocated object.
76 //!The object pointed to is guaranteed to be deleted when the last shared_ptr pointing to
77 //!it is destroyed or reset.
79 //!shared_ptr is parameterized on
80 //!T (the type of the object pointed to), VoidAllocator (the void allocator to be used
81 //!to allocate the auxiliary data) and Deleter (the deleter whose
82 //!operator() will be used to delete the object.
84 //!The internal pointer will be of the same pointer type as typename
85 //!VoidAllocator::pointer type (that is, if typename VoidAllocator::pointer is
86 //!offset_ptr<void>, the internal pointer will be offset_ptr<T>).
88 //!Because the implementation uses reference counting, cycles of shared_ptr
89 //!instances will not be reclaimed. For example, if main() holds a
90 //!shared_ptr to A, which directly or indirectly holds a shared_ptr back
91 //!to A, A's use count will be 2. Destruction of the original shared_ptr
92 //!will leave A dangling with a use count of 1.
93 //!Use weak_ptr to "break cycles."
94 template<class T, class VoidAllocator, class Deleter>
97 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
99 typedef shared_ptr<T, VoidAllocator, Deleter> this_type;
100 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
104 typedef T element_type;
105 typedef T value_type;
106 typedef typename boost::intrusive::
107 pointer_traits<typename VoidAllocator::pointer>::template
108 rebind_pointer<T>::type pointer;
109 typedef typename ipcdetail::add_reference
110 <value_type>::type reference;
111 typedef typename ipcdetail::add_reference
112 <const value_type>::type const_reference;
113 typedef typename boost::intrusive::
114 pointer_traits<typename VoidAllocator::pointer>::template
115 rebind_pointer<const Deleter>::type const_deleter_pointer;
116 typedef typename boost::intrusive::
117 pointer_traits<typename VoidAllocator::pointer>::template
118 rebind_pointer<const VoidAllocator>::type const_allocator_pointer;
120 BOOST_COPYABLE_AND_MOVABLE(shared_ptr)
123 //!Constructs an empty shared_ptr.
124 //!Use_count() == 0 && get()== 0.
126 : m_pn() // never throws
129 //!Constructs a shared_ptr that owns the pointer p. Auxiliary data will be allocated
130 //!with a copy of a and the object will be deleted with a copy of d.
131 //!Requirements: Deleter and A's copy constructor must not throw.
132 explicit shared_ptr(const pointer&p, const VoidAllocator &a = VoidAllocator(), const Deleter &d = Deleter())
135 //Check that the pointer passed is of the same type that
136 //the pointer the allocator defines or it's a raw pointer
137 typedef typename boost::intrusive::
138 pointer_traits<pointer>::template
139 rebind_pointer<T>::type ParameterPointer;
141 BOOST_STATIC_ASSERT((ipcdetail::is_same<pointer, ParameterPointer>::value) ||
142 (ipcdetail::is_pointer<pointer>::value));
143 ipcdetail::sp_enable_shared_from_this<T, VoidAllocator, Deleter>( m_pn, ipcdetail::to_raw_pointer(p), ipcdetail::to_raw_pointer(p) );
146 //!Copy constructs a shared_ptr. If r is empty, constructs an empty shared_ptr. Otherwise, constructs
147 //!a shared_ptr that shares ownership with r. Never throws.
148 shared_ptr(const shared_ptr &r)
149 : m_pn(r.m_pn) // never throws
152 //!Constructs a shared_ptr that shares ownership with other and stores p.
153 //!Postconditions: get() == p && use_count() == r.use_count().
155 shared_ptr(const shared_ptr &other, const pointer &p)
156 : m_pn(other.m_pn, p)
159 //!If r is empty, constructs an empty shared_ptr. Otherwise, constructs
160 //!a shared_ptr that shares ownership with r. Never throws.
162 shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r)
163 : m_pn(r.m_pn) // never throws
166 //!Constructs a shared_ptr that shares ownership with r and stores
167 //!a copy of the pointer stored in r.
169 explicit shared_ptr(weak_ptr<Y, VoidAllocator, Deleter> const & r)
170 : m_pn(r.m_pn) // may throw
173 //!Move-Constructs a shared_ptr that takes ownership of other resource and
174 //!other is put in default-constructed state.
176 explicit shared_ptr(BOOST_RV_REF(shared_ptr) other)
178 { this->swap(other); }
180 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
182 shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r, ipcdetail::static_cast_tag)
183 : m_pn( pointer(static_cast<T*>(ipcdetail::to_raw_pointer(r.m_pn.to_raw_pointer())))
188 shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r, ipcdetail::const_cast_tag)
189 : m_pn( pointer(const_cast<T*>(ipcdetail::to_raw_pointer(r.m_pn.to_raw_pointer())))
194 shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r, ipcdetail::dynamic_cast_tag)
195 : m_pn( pointer(dynamic_cast<T*>(ipcdetail::to_raw_pointer(r.m_pn.to_raw_pointer())))
198 if(!m_pn.to_raw_pointer()){ // need to allocate new counter -- the cast failed
199 m_pn = ipcdetail::shared_count<T, VoidAllocator, Deleter>();
202 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
204 //!Equivalent to shared_ptr(r).swap(*this).
207 shared_ptr & operator=(shared_ptr<Y, VoidAllocator, Deleter> const & r)
209 m_pn = r.m_pn; // shared_count::op= doesn't throw
213 //!Equivalent to shared_ptr(r).swap(*this).
215 shared_ptr & operator=(BOOST_COPY_ASSIGN_REF(shared_ptr) r)
217 m_pn = r.m_pn; // shared_count::op= doesn't throw
221 //!Move-assignment. Equivalent to shared_ptr(other).swap(*this).
223 shared_ptr & operator=(BOOST_RV_REF(shared_ptr) other) // never throws
225 this_type(other).swap(*this);
229 //!This is equivalent to:
230 //!this_type().swap(*this);
233 this_type().swap(*this);
236 //!This is equivalent to:
237 //!this_type(p, a, d).swap(*this);
238 template<class Pointer>
239 void reset(const Pointer &p, const VoidAllocator &a = VoidAllocator(), const Deleter &d = Deleter())
241 //Check that the pointer passed is of the same type that
242 //the pointer the allocator defines or it's a raw pointer
243 typedef typename boost::intrusive::
244 pointer_traits<Pointer>::template
245 rebind_pointer<T>::type ParameterPointer;
246 BOOST_STATIC_ASSERT((ipcdetail::is_same<pointer, ParameterPointer>::value) ||
247 (ipcdetail::is_pointer<Pointer>::value));
248 this_type(p, a, d).swap(*this);
252 void reset(shared_ptr<Y, VoidAllocator, Deleter> const & r, const pointer &p)
254 this_type(r, p).swap(*this);
257 //!Returns a reference to the
259 reference operator* () const // never throws
260 { BOOST_ASSERT(m_pn.to_raw_pointer() != 0); return *m_pn.to_raw_pointer(); }
262 //!Returns the pointer pointing
263 //!to the owned object
264 pointer operator-> () const // never throws
265 { BOOST_ASSERT(m_pn.to_raw_pointer() != 0); return m_pn.to_raw_pointer(); }
267 //!Returns the pointer pointing
268 //!to the owned object
269 pointer get() const // never throws
270 { return m_pn.to_raw_pointer(); }
272 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
273 // implicit conversion to "bool"
274 void unspecified_bool_type_func() const {}
275 typedef void (this_type::*unspecified_bool_type)() const;
277 operator unspecified_bool_type() const // never throws
278 { return !m_pn.to_raw_pointer() ? 0 : &this_type::unspecified_bool_type_func; }
279 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
282 //!Returns true if this->get() != 0, false otherwise
283 bool operator! () const // never throws
284 { return !m_pn.to_raw_pointer(); }
286 //!Returns use_count() == 1.
287 //!unique() might be faster than use_count()
288 bool unique() const // never throws
289 { return m_pn.unique(); }
291 //!Returns the number of shared_ptr objects, *this included,
292 //!that share ownership with *this, or an unspecified nonnegative
293 //!value when *this is empty.
294 //!use_count() is not necessarily efficient. Use only for
295 //!debugging and testing purposes, not for production code.
296 long use_count() const // never throws
297 { return m_pn.use_count(); }
299 //!Exchanges the contents of the two
301 void swap(shared_ptr<T, VoidAllocator, Deleter> & other) // never throws
302 { m_pn.swap(other.m_pn); }
304 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
306 template<class T2, class A2, class Deleter2>
307 bool _internal_less(shared_ptr<T2, A2, Deleter2> const & rhs) const
308 { return m_pn < rhs.m_pn; }
310 const_deleter_pointer get_deleter() const
311 { return m_pn.get_deleter(); }
313 // const_allocator_pointer get_allocator() const
314 // { return m_pn.get_allocator(); }
318 template<class T2, class A2, class Deleter2> friend class shared_ptr;
319 template<class T2, class A2, class Deleter2> friend class weak_ptr;
321 ipcdetail::shared_count<T, VoidAllocator, Deleter> m_pn; // reference counter
322 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
325 template<class T, class VoidAllocator, class Deleter, class U, class VoidAllocator2, class Deleter2> inline
326 bool operator==(shared_ptr<T, VoidAllocator, Deleter> const & a, shared_ptr<U, VoidAllocator2, Deleter2> const & b)
327 { return a.get() == b.get(); }
329 template<class T, class VoidAllocator, class Deleter, class U, class VoidAllocator2, class Deleter2> inline
330 bool operator!=(shared_ptr<T, VoidAllocator, Deleter> const & a, shared_ptr<U, VoidAllocator2, Deleter2> const & b)
331 { return a.get() != b.get(); }
333 template<class T, class VoidAllocator, class Deleter, class U, class VoidAllocator2, class Deleter2> inline
334 bool operator<(shared_ptr<T, VoidAllocator, Deleter> const & a, shared_ptr<U, VoidAllocator2, Deleter2> const & b)
335 { return a._internal_less(b); }
337 template<class T, class VoidAllocator, class Deleter> inline
338 void swap(shared_ptr<T, VoidAllocator, Deleter> & a, shared_ptr<T, VoidAllocator, Deleter> & b)
341 template<class T, class VoidAllocator, class Deleter, class U> inline
342 shared_ptr<T, VoidAllocator, Deleter> static_pointer_cast(shared_ptr<U, VoidAllocator, Deleter> const & r)
343 { return shared_ptr<T, VoidAllocator, Deleter>(r, ipcdetail::static_cast_tag()); }
345 template<class T, class VoidAllocator, class Deleter, class U> inline
346 shared_ptr<T, VoidAllocator, Deleter> const_pointer_cast(shared_ptr<U, VoidAllocator, Deleter> const & r)
347 { return shared_ptr<T, VoidAllocator, Deleter>(r, ipcdetail::const_cast_tag()); }
349 template<class T, class VoidAllocator, class Deleter, class U> inline
350 shared_ptr<T, VoidAllocator, Deleter> dynamic_pointer_cast(shared_ptr<U, VoidAllocator, Deleter> const & r)
351 { return shared_ptr<T, VoidAllocator, Deleter>(r, ipcdetail::dynamic_cast_tag()); }
353 // to_raw_pointer() enables boost::mem_fn to recognize shared_ptr
354 template<class T, class VoidAllocator, class Deleter> inline
355 T * to_raw_pointer(shared_ptr<T, VoidAllocator, Deleter> const & p)
359 template<class E, class T, class Y, class VoidAllocator, class Deleter> inline
360 std::basic_ostream<E, T> & operator<<
361 (std::basic_ostream<E, T> & os, shared_ptr<Y, VoidAllocator, Deleter> const & p)
362 { os << p.get(); return os; }
364 //!Returns the type of a shared pointer
365 //!of type T with the allocator boost::interprocess::allocator allocator
366 //!and boost::interprocess::deleter deleter
367 //!that can be constructed in the given managed segment type.
368 template<class T, class ManagedMemory>
369 struct managed_shared_ptr
371 typedef typename ManagedMemory::template allocator<void>::type void_allocator;
372 typedef typename ManagedMemory::template deleter<T>::type deleter;
373 typedef shared_ptr< T, void_allocator, deleter> type;
376 //!Returns an instance of a shared pointer constructed
377 //!with the default allocator and deleter from a pointer
378 //!of type T that has been allocated in the passed managed segment
379 template<class T, class ManagedMemory>
380 inline typename managed_shared_ptr<T, ManagedMemory>::type
381 make_managed_shared_ptr(T *constructed_object, ManagedMemory &managed_memory)
383 return typename managed_shared_ptr<T, ManagedMemory>::type
385 , managed_memory.template get_allocator<void>()
386 , managed_memory.template get_deleter<T>()
390 //!Returns an instance of a shared pointer constructed
391 //!with the default allocator and deleter from a pointer
392 //!of type T that has been allocated in the passed managed segment.
393 //!Does not throw, return null shared pointer in error.
394 template<class T, class ManagedMemory>
395 inline typename managed_shared_ptr<T, ManagedMemory>::type
396 make_managed_shared_ptr(T *constructed_object, ManagedMemory &managed_memory, const std::nothrow_t &)
399 return typename managed_shared_ptr<T, ManagedMemory>::type
401 , managed_memory.template get_allocator<void>()
402 , managed_memory.template get_deleter<T>()
406 return typename managed_shared_ptr<T, ManagedMemory>::type();
411 } // namespace interprocess
413 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
415 #if defined(_MSC_VER) && (_MSC_VER < 1400)
416 // to_raw_pointer() enables boost::mem_fn to recognize shared_ptr
417 template<class T, class VoidAllocator, class Deleter> inline
418 T * to_raw_pointer(boost::interprocess::shared_ptr<T, VoidAllocator, Deleter> const & p)
422 #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
426 #include <boost/interprocess/detail/config_end.hpp>
428 #endif // #ifndef BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED