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_
19 #include <boost/utility/enable_if.hpp>
20 #include <boost/static_assert.hpp>
21 #include <boost/mpl/if.hpp>
22 #include <boost/type_traits/is_reference.hpp>
23 #include <boost/type_traits/is_empty.hpp>
24 #include <boost/type_traits/remove_reference.hpp>
25 #include <boost/type_traits/is_array.hpp>
26 #include <boost/type_traits/is_pointer.hpp>
31 namespace detail_unique_ptr
35 struct two {one _[2];};
37 // An is_convertible<From, To> that considers From an rvalue (consistent with C++0X).
38 // This is a simplified version neglecting the types function, array, void and abstract types
39 // I had to make a special case out of is_convertible<T,T> to make move-only
44 template <class T> one test1(const T&);
45 template <class T> two test1(...);
46 template <class T> one test2(T);
47 template <class T> two test2(...);
48 template <class T> T source();
51 template <class T1, class T2>
54 static const bool value = sizeof(is_conv_imp::test1<T2>(is_conv_imp::source<T1>())) == 1;
58 struct is_convertible<T, T>
60 static const bool value = sizeof(is_conv_imp::test2<T>(is_conv_imp::source<T>())) == 1;
69 explicit rv(T& r) : r_(r) {}
70 T* operator->() {return &r_;}
71 T& operator*() {return r_;}
80 } // detail_unique_ptr
86 !detail_unique_ptr::is_convertible<T, detail_unique_ptr::rv<T> >::value,
98 !detail_unique_ptr::is_convertible<T, detail_unique_ptr::rv<T> >::value,
110 detail_unique_ptr::is_convertible<T, detail_unique_ptr::rv<T> >::value,
115 return T(detail_unique_ptr::rv<T>(t));
122 is_reference<T>::value,
125 forward(typename detail_unique_ptr::identity<T>::type t)
134 !is_reference<T>::value,
137 forward(typename detail_unique_ptr::identity<T>::type& t)
139 return boost::move(t);
146 !is_reference<T>::value,
149 forward(const typename detail_unique_ptr::identity<T>::type& t)
151 return boost::move(const_cast<T&>(t));
154 namespace detail_unique_ptr {
156 // A move-aware but stripped-down compressed_pair which only optimizes storage for T2
157 template <class T1, class T2, bool = is_empty<T2>::value>
158 class unique_ptr_storage
163 typedef typename add_reference<T2>::type T2_reference;
164 typedef typename add_reference<const T2>::type T2_const_reference;
166 unique_ptr_storage(const unique_ptr_storage&);
167 unique_ptr_storage& operator=(const unique_ptr_storage&);
169 operator rv<unique_ptr_storage>() {return rv<unique_ptr_storage>(*this);}
171 unique_ptr_storage() : t1_(), t2_() {}
173 explicit unique_ptr_storage(T1 t1)
174 : t1_(boost::move(t1)), t2_() {}
176 unique_ptr_storage(T1 t1, T2 t2)
177 : t1_(boost::move(t1)), t2_(boost::forward<T2>(t2)) {}
179 T1& first() {return t1_;}
180 const T1& first() const {return t1_;}
182 T2_reference second() {return t2_;}
183 T2_const_reference second() const {return t2_;}
186 template <class T1, class T2>
187 class unique_ptr_storage<T1, T2, true>
193 unique_ptr_storage(const unique_ptr_storage&);
194 unique_ptr_storage& operator=(const unique_ptr_storage&);
196 operator rv<unique_ptr_storage>() {return rv<unique_ptr_storage>(*this);}
198 unique_ptr_storage() : t1_() {}
200 explicit unique_ptr_storage(T1 t1)
201 : t1_(boost::move(t1)) {}
203 unique_ptr_storage(T1 t1, T2 t2)
204 : t2_(boost::move(t2)), t1_(boost::move(t1)) {}
206 T1& first() {return t1_;}
207 const T1& first() const {return t1_;}
209 T2& second() {return *this;}
210 const T2& second() const {return *this;}
213 template <class T1, class T2, bool b>
216 swap(unique_ptr_storage<T1, T2, b>& x, unique_ptr_storage<T1, T2, b>& y)
219 swap(x.first(), y.first());
220 swap(x.second(), y.second());
223 } // detail_unique_ptr
226 struct default_delete
230 default_delete(const default_delete<U>&,
231 typename enable_if_c<detail_unique_ptr::is_convertible<U*, T*>::value>::type* = 0)
234 void operator()(T* ptr) const
236 BOOST_STATIC_ASSERT(sizeof(T) > 0);
242 struct default_delete<T[]>
244 void operator()(T* ptr) const
246 BOOST_STATIC_ASSERT(sizeof(T) > 0);
252 template <class U> void operator()(U*) const;
255 namespace detail_unique_ptr
258 namespace pointer_type_imp
261 template <class U> static two test(...);
262 template <class U> static one test(typename U::pointer* = 0);
264 } // pointer_type_imp
267 struct has_pointer_type
269 static const bool value = sizeof(pointer_type_imp::test<T>(0)) == 1;
272 namespace pointer_type_imp
275 template <class T, class D, bool = has_pointer_type<D>::value>
278 typedef typename D::pointer type;
281 template <class T, class D>
282 struct pointer_type<T, D, false>
287 } // pointer_type_imp
289 template <class T, class D>
292 typedef typename pointer_type_imp::pointer_type<T,
293 typename boost::remove_reference<D>::type>::type type;
296 } // detail_unique_ptr
298 template <class T, class D = default_delete<T> >
302 typedef T element_type;
303 typedef D deleter_type;
304 typedef typename detail_unique_ptr::pointer_type<element_type, deleter_type>::type pointer;
307 detail_unique_ptr::unique_ptr_storage<pointer, deleter_type> ptr_;
309 typedef typename add_reference<deleter_type>::type deleter_reference;
310 typedef typename add_reference<const deleter_type>::type deleter_const_reference;
312 struct nat {int for_bool_;};
314 unique_ptr(unique_ptr&);
315 unique_ptr& operator=(unique_ptr&);
318 operator detail_unique_ptr::rv<unique_ptr>() {return detail_unique_ptr::rv<unique_ptr>(*this);}
319 unique_ptr(detail_unique_ptr::rv<unique_ptr> r) : ptr_(r->release(), boost::forward<deleter_type>(r->get_deleter())) {}
320 unique_ptr& operator=(detail_unique_ptr::rv<unique_ptr> r)
323 ptr_.second() = boost::move(r->get_deleter());
329 BOOST_STATIC_ASSERT(!is_reference<deleter_type>::value);
330 BOOST_STATIC_ASSERT(!is_pointer<deleter_type>::value);
333 explicit unique_ptr(pointer p)
336 BOOST_STATIC_ASSERT(!is_reference<deleter_type>::value);
337 BOOST_STATIC_ASSERT(!is_pointer<deleter_type>::value);
340 unique_ptr(pointer p, typename mpl::if_<is_reference<D>,
341 volatile typename remove_reference<D>::type&, D>::type d)
342 : ptr_(boost::move(p), boost::forward<D>(const_cast<typename add_reference<D>::type>(d))) {}
344 template <class U, class E>
345 unique_ptr(unique_ptr<U, E> u,
348 !boost::is_array<U>::value &&
349 detail_unique_ptr::is_convertible<typename unique_ptr<U>::pointer, pointer>::value &&
350 detail_unique_ptr::is_convertible<E, deleter_type>::value &&
352 !is_reference<deleter_type>::value ||
353 is_same<deleter_type, E>::value
356 : ptr_(u.release(), boost::forward<D>(boost::forward<E>(u.get_deleter()))) {}
358 ~unique_ptr() {reset();}
360 unique_ptr& operator=(int nat::*)
366 template <class U, class E>
368 operator=(unique_ptr<U, E> u)
371 ptr_.second() = boost::move(u.get_deleter());
375 typename add_reference<T>::type operator*() const {return *get();}
376 pointer operator->() const {return get();}
377 pointer get() const {return ptr_.first();}
378 deleter_reference get_deleter() {return ptr_.second();}
379 deleter_const_reference get_deleter() const {return ptr_.second();}
380 operator int nat::*() const {return get() ? &nat::for_bool_ : 0;}
382 void reset(pointer p = pointer())
393 ptr_.first() = pointer();
397 void swap(unique_ptr& u) {detail_unique_ptr::swap(ptr_, u.ptr_);}
400 template <class T, class D>
401 class unique_ptr<T[], D>
404 typedef T element_type;
405 typedef D deleter_type;
406 typedef typename detail_unique_ptr::pointer_type<element_type, deleter_type>::type pointer;
409 detail_unique_ptr::unique_ptr_storage<pointer, deleter_type> ptr_;
411 typedef typename add_reference<deleter_type>::type deleter_reference;
412 typedef typename add_reference<const deleter_type>::type deleter_const_reference;
414 struct nat {int for_bool_;};
416 unique_ptr(unique_ptr&);
417 unique_ptr& operator=(unique_ptr&);
420 operator detail_unique_ptr::rv<unique_ptr>() {return detail_unique_ptr::rv<unique_ptr>(*this);}
421 unique_ptr(detail_unique_ptr::rv<unique_ptr> r) : ptr_(r->release(), boost::forward<deleter_type>(r->get_deleter())) {}
422 unique_ptr& operator=(detail_unique_ptr::rv<unique_ptr> r)
425 ptr_.second() = boost::move(r->get_deleter());
431 BOOST_STATIC_ASSERT(!is_reference<deleter_type>::value);
432 BOOST_STATIC_ASSERT(!is_pointer<deleter_type>::value);
435 explicit unique_ptr(pointer p)
438 BOOST_STATIC_ASSERT(!is_reference<deleter_type>::value);
439 BOOST_STATIC_ASSERT(!is_pointer<deleter_type>::value);
442 unique_ptr(pointer p, typename mpl::if_<is_reference<D>,
443 volatile typename remove_reference<D>::type&, D>::type d)
444 : ptr_(boost::move(p), boost::forward<D>(const_cast<typename add_reference<D>::type>(d))) {}
446 ~unique_ptr() {reset();}
448 T& operator[](size_t i) const {return get()[i];}
449 pointer get() const {return ptr_.first();}
450 deleter_reference get_deleter() {return ptr_.second();}
451 deleter_const_reference get_deleter() const {return ptr_.second();}
452 operator int nat::*() const {return get() ? &nat::for_bool_ : 0;}
454 void reset(pointer p = pointer())
465 ptr_.first() = pointer();
469 void swap(unique_ptr& u) {detail_unique_ptr::swap(ptr_, u.ptr_);}
472 explicit unique_ptr(U,
473 typename enable_if_c<detail_unique_ptr::is_convertible<U, pointer>::value>::type* = 0);
476 unique_ptr(U, typename mpl::if_<is_reference<D>,
477 volatile typename remove_reference<D>::type&, D>::type,
478 typename enable_if_c<detail_unique_ptr::is_convertible<U, pointer>::value>::type* = 0);
481 template<class T, class D>
484 swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y)
489 template<class T1, class D1, class T2, class D2>
492 operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
494 return x.get() == y.get();
497 template<class T1, class D1, class T2, class D2>
500 operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
505 template<class T1, class D1, class T2, class D2>
508 operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
510 return x.get() < y.get();
513 template<class T1, class D1, class T2, class D2>
516 operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
521 template<class T1, class D1, class T2, class D2>
524 operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
529 template<class T1, class D1, class T2, class D2>
532 operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
539 #endif // _BOOST_UNIQUE_PTR_HPP_