1 ///////////////////////////////////////////////////////////////////////////////
2 // unique_ptr.hpp header file
4 // Copyright 2009 Howard Hinnant, Ion Gaztañaga.
5 // Distributed under the Boost Software License, Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 // See http://www.boost.org/libs/foreach for documentation
10 // This is a C++03 emulation of std::unique_ptr placed in namespace boost.
11 // Reference http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2800.pdf
12 // for the latest unique_ptr specification, and
13 // reference http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html
14 // for any pending issues against this specification.
16 #ifndef _BOOST_UNIQUE_PTR_HPP_
17 #define _BOOST_UNIQUE_PTR_HPP_
20 #include <boost/utility/enable_if.hpp>
21 #include <boost/type_traits.hpp>
22 #include <boost/static_assert.hpp>
23 #include <boost/mpl/if.hpp>
28 namespace detail_unique_ptr
32 struct two {one _[2];};
34 // An is_convertible<From, To> that considers From an rvalue (consistent with C++0X).
35 // This is a simplified version neglecting the types function, array, void and abstract types
36 // I had to make a special case out of is_convertible<T,T> to make move-only
41 template <class T> one test1(const T&);
42 template <class T> two test1(...);
43 template <class T> one test2(T);
44 template <class T> two test2(...);
45 template <class T> T source();
48 template <class T1, class T2>
51 static const bool value = sizeof(is_conv_imp::test1<T2>(is_conv_imp::source<T1>())) == 1;
55 struct is_convertible<T, T>
57 static const bool value = sizeof(is_conv_imp::test2<T>(is_conv_imp::source<T>())) == 1;
66 explicit rv(T& r) : r_(r) {}
67 T* operator->() {return &r_;}
68 T& operator*() {return r_;}
77 } // detail_unique_ptr
83 !detail_unique_ptr::is_convertible<T, detail_unique_ptr::rv<T> >::value,
95 !detail_unique_ptr::is_convertible<T, detail_unique_ptr::rv<T> >::value,
107 detail_unique_ptr::is_convertible<T, detail_unique_ptr::rv<T> >::value,
112 return T(detail_unique_ptr::rv<T>(t));
119 is_reference<T>::value,
122 forward(typename detail_unique_ptr::identity<T>::type t)
131 !is_reference<T>::value,
134 forward(typename detail_unique_ptr::identity<T>::type& t)
136 return boost::move(t);
143 !is_reference<T>::value,
146 forward(const typename detail_unique_ptr::identity<T>::type& t)
148 return boost::move(const_cast<T&>(t));
151 namespace detail_unique_ptr {
153 // A move-aware but stripped-down compressed_pair which only optimizes storage for T2
154 template <class T1, class T2, bool = is_empty<T2>::value>
155 class unique_ptr_storage
160 typedef typename add_reference<T2>::type T2_reference;
161 typedef typename add_reference<const T2>::type T2_const_reference;
163 unique_ptr_storage(const unique_ptr_storage&);
164 unique_ptr_storage& operator=(const unique_ptr_storage&);
166 operator rv<unique_ptr_storage>() {return rv<unique_ptr_storage>(*this);}
168 unique_ptr_storage() : t1_(), t2_() {}
170 explicit unique_ptr_storage(T1 t1)
171 : t1_(boost::move(t1)), t2_() {}
173 unique_ptr_storage(T1 t1, T2 t2)
174 : t1_(boost::move(t1)), t2_(boost::forward<T2>(t2)) {}
176 T1& first() {return t1_;}
177 const T1& first() const {return t1_;}
179 T2_reference second() {return t2_;}
180 T2_const_reference second() const {return t2_;}
183 template <class T1, class T2>
184 class unique_ptr_storage<T1, T2, true>
190 unique_ptr_storage(const unique_ptr_storage&);
191 unique_ptr_storage& operator=(const unique_ptr_storage&);
193 operator rv<unique_ptr_storage>() {return rv<unique_ptr_storage>(*this);}
195 unique_ptr_storage() : t1_() {}
197 explicit unique_ptr_storage(T1 t1)
198 : t1_(boost::move(t1)) {}
200 unique_ptr_storage(T1 t1, T2 t2)
201 : t2_(boost::move(t2)), t1_(boost::move(t1)) {}
203 T1& first() {return t1_;}
204 const T1& first() const {return t1_;}
206 T2& second() {return *this;}
207 const T2& second() const {return *this;}
210 template <class T1, class T2, bool b>
213 swap(unique_ptr_storage<T1, T2, b>& x, unique_ptr_storage<T1, T2, b>& y)
216 swap(x.first(), y.first());
217 swap(x.second(), y.second());
220 } // detail_unique_ptr
223 struct default_delete
227 default_delete(const default_delete<U>&,
228 typename enable_if_c<detail_unique_ptr::is_convertible<U*, T*>::value>::type* = 0)
231 void operator()(T* ptr) const
233 BOOST_STATIC_ASSERT(sizeof(T) > 0);
239 struct default_delete<T[]>
241 void operator()(T* ptr) const
243 BOOST_STATIC_ASSERT(sizeof(T) > 0);
249 template <class U> void operator()(U*) const;
252 namespace detail_unique_ptr
255 namespace pointer_type_imp
258 template <class U> static two test(...);
259 template <class U> static one test(typename U::pointer* = 0);
261 } // pointer_type_imp
264 struct has_pointer_type
266 static const bool value = sizeof(pointer_type_imp::test<T>(0)) == 1;
269 namespace pointer_type_imp
272 template <class T, class D, bool = has_pointer_type<D>::value>
275 typedef typename D::pointer type;
278 template <class T, class D>
279 struct pointer_type<T, D, false>
284 } // pointer_type_imp
286 template <class T, class D>
289 typedef typename pointer_type_imp::pointer_type<T,
290 typename boost::remove_reference<D>::type>::type type;
293 } // detail_unique_ptr
295 template <class T, class D = default_delete<T> >
299 typedef T element_type;
300 typedef D deleter_type;
301 typedef typename detail_unique_ptr::pointer_type<element_type, deleter_type>::type pointer;
304 detail_unique_ptr::unique_ptr_storage<pointer, deleter_type> ptr_;
306 typedef typename add_reference<deleter_type>::type deleter_reference;
307 typedef typename add_reference<const deleter_type>::type deleter_const_reference;
309 struct nat {int for_bool_;};
311 unique_ptr(unique_ptr&);
312 unique_ptr& operator=(unique_ptr&);
315 operator detail_unique_ptr::rv<unique_ptr>() {return detail_unique_ptr::rv<unique_ptr>(*this);}
316 unique_ptr(detail_unique_ptr::rv<unique_ptr> r) : ptr_(r->release(), boost::forward<deleter_type>(r->get_deleter())) {}
317 unique_ptr& operator=(detail_unique_ptr::rv<unique_ptr> r)
320 ptr_.second() = boost::move(r->get_deleter());
326 BOOST_STATIC_ASSERT(!is_reference<deleter_type>::value);
327 BOOST_STATIC_ASSERT(!is_pointer<deleter_type>::value);
330 explicit unique_ptr(pointer p)
333 BOOST_STATIC_ASSERT(!is_reference<deleter_type>::value);
334 BOOST_STATIC_ASSERT(!is_pointer<deleter_type>::value);
337 unique_ptr(pointer p, typename mpl::if_<is_reference<D>,
338 volatile typename remove_reference<D>::type&, D>::type d)
339 : ptr_(boost::move(p), boost::forward<D>(const_cast<typename add_reference<D>::type>(d))) {}
341 template <class U, class E>
342 unique_ptr(unique_ptr<U, E> u,
345 !boost::is_array<U>::value &&
346 detail_unique_ptr::is_convertible<typename unique_ptr<U>::pointer, pointer>::value &&
347 detail_unique_ptr::is_convertible<E, deleter_type>::value &&
349 !is_reference<deleter_type>::value ||
350 is_same<deleter_type, E>::value
353 : ptr_(u.release(), boost::forward<D>(boost::forward<E>(u.get_deleter()))) {}
355 ~unique_ptr() {reset();}
357 unique_ptr& operator=(int nat::*)
363 template <class U, class E>
365 operator=(unique_ptr<U, E> u)
368 ptr_.second() = boost::move(u.get_deleter());
372 typename add_reference<T>::type operator*() const {return *get();}
373 pointer operator->() const {return get();}
374 pointer get() const {return ptr_.first();}
375 deleter_reference get_deleter() {return ptr_.second();}
376 deleter_const_reference get_deleter() const {return ptr_.second();}
377 operator int nat::*() const {return get() ? &nat::for_bool_ : 0;}
379 void reset(pointer p = pointer())
390 ptr_.first() = pointer();
394 void swap(unique_ptr& u) {detail_unique_ptr::swap(ptr_, u.ptr_);}
397 template <class T, class D>
398 class unique_ptr<T[], D>
401 typedef T element_type;
402 typedef D deleter_type;
403 typedef typename detail_unique_ptr::pointer_type<element_type, deleter_type>::type pointer;
406 detail_unique_ptr::unique_ptr_storage<pointer, deleter_type> ptr_;
408 typedef typename add_reference<deleter_type>::type deleter_reference;
409 typedef typename add_reference<const deleter_type>::type deleter_const_reference;
411 struct nat {int for_bool_;};
413 unique_ptr(unique_ptr&);
414 unique_ptr& operator=(unique_ptr&);
417 operator detail_unique_ptr::rv<unique_ptr>() {return detail_unique_ptr::rv<unique_ptr>(*this);}
418 unique_ptr(detail_unique_ptr::rv<unique_ptr> r) : ptr_(r->release(), boost::forward<deleter_type>(r->get_deleter())) {}
419 unique_ptr& operator=(detail_unique_ptr::rv<unique_ptr> r)
422 ptr_.second() = boost::move(r->get_deleter());
428 BOOST_STATIC_ASSERT(!is_reference<deleter_type>::value);
429 BOOST_STATIC_ASSERT(!is_pointer<deleter_type>::value);
432 explicit unique_ptr(pointer p)
435 BOOST_STATIC_ASSERT(!is_reference<deleter_type>::value);
436 BOOST_STATIC_ASSERT(!is_pointer<deleter_type>::value);
439 unique_ptr(pointer p, typename mpl::if_<is_reference<D>,
440 volatile typename remove_reference<D>::type&, D>::type d)
441 : ptr_(boost::move(p), boost::forward<D>(const_cast<typename add_reference<D>::type>(d))) {}
443 ~unique_ptr() {reset();}
445 T& operator[](size_t i) const {return get()[i];}
446 pointer get() const {return ptr_.first();}
447 deleter_reference get_deleter() {return ptr_.second();}
448 deleter_const_reference get_deleter() const {return ptr_.second();}
449 operator int nat::*() const {return get() ? &nat::for_bool_ : 0;}
451 void reset(pointer p = pointer())
462 ptr_.first() = pointer();
466 void swap(unique_ptr& u) {detail_unique_ptr::swap(ptr_, u.ptr_);}
469 explicit unique_ptr(U,
470 typename enable_if_c<detail_unique_ptr::is_convertible<U, pointer>::value>::type* = 0);
473 unique_ptr(U, typename mpl::if_<is_reference<D>,
474 volatile typename remove_reference<D>::type&, D>::type,
475 typename enable_if_c<detail_unique_ptr::is_convertible<U, pointer>::value>::type* = 0);
478 template<class T, class D>
481 swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y)
486 template<class T1, class D1, class T2, class D2>
489 operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
491 return x.get() == y.get();
494 template<class T1, class D1, class T2, class D2>
497 operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
502 template<class T1, class D1, class T2, class D2>
505 operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
507 return x.get() < y.get();
510 template<class T1, class D1, class T2, class D2>
513 operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
518 template<class T1, class D1, class T2, class D2>
521 operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
526 template<class T1, class D1, class T2, class D2>
529 operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
536 #endif // _BOOST_UNIQUE_PTR_HPP_