1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2014-2014. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/move for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10
11 #ifndef BOOST_MOVE_UNIQUE_PTR_HPP_INCLUDED
12 #define BOOST_MOVE_UNIQUE_PTR_HPP_INCLUDED
13
14 #ifndef BOOST_CONFIG_HPP
15 # include <boost/config.hpp>
16 #endif
17 #
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
19 # pragma once
20 #endif
21
22 #include <boost/move/detail/config_begin.hpp>
23 #include <boost/move/detail/workaround.hpp>
24 #include <boost/move/detail/unique_ptr_meta_utils.hpp>
25 #include <boost/move/default_delete.hpp>
26 #include <boost/move/utility_core.hpp>
27 #include <boost/move/adl_move_swap.hpp>
28 #include <boost/static_assert.hpp>
29 #include <boost/assert.hpp>
30
31 #include <cstddef> //For std::nullptr_t and std::size_t
32
33 //!\file
34 //! Describes the smart pointer unique_ptr, a drop-in replacement for std::unique_ptr,
35 //! usable also from C++03 compilers.
36 //!
37 //! Main differences from std::unique_ptr to avoid heavy dependencies,
38 //! specially in C++03 compilers:
39 //! - <tt>operator < </tt> uses pointer <tt>operator < </tt>instead of <tt>std::less<common_type></tt>.
40 //! This avoids dependencies on <tt>std::common_type</tt> and <tt>std::less</tt>
41 //! (<tt><type_traits>/<functional></tt> headers. In C++03 this avoid pulling Boost.Typeof and other
42 //! cascading dependencies. As in all Boost platforms <tt>operator <</tt> on raw pointers and
43 //! other smart pointers provides strict weak ordering in practice this should not be a problem for users.
44 //! - assignable from literal 0 for compilers without nullptr
45 //! - <tt>unique_ptr<T[]></tt> is constructible and assignable from <tt>unique_ptr<U[]></tt> if
46 //! cv-less T and cv-less U are the same type and T is more CV qualified than U.
47
48 namespace boost{
49 namespace move_upd {
50
51 ////////////////////////////////////////////
52 // deleter types
53 ////////////////////////////////////////////
54 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
55 template <class T>
56 class is_noncopyable
57 {
58 typedef char true_t;
59 class false_t { char dummy[2]; };
60 template<class U> static false_t dispatch(...);
61 template<class U> static true_t dispatch(typename U::boost_move_no_copy_constructor_or_assign*);
62 public:
63 static const bool value = sizeof(dispatch<T>(0)) == sizeof(true_t);
64 };
65 #endif //defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
66
67 template <class D>
68 struct deleter_types
69 {
70 typedef typename bmupmu::add_lvalue_reference<D>::type del_ref;
71 typedef typename bmupmu::add_const_lvalue_reference<D>::type del_cref;
72 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
73 typedef typename bmupmu::if_c
74 < bmupmu::is_lvalue_reference<D>::value, D, del_cref >::type deleter_arg_type1;
75 typedef typename bmupmu::remove_reference<D>::type && deleter_arg_type2;
76 #else
77 typedef typename bmupmu::if_c
78 < is_noncopyable<D>::value, bmupmu::nat, del_cref>::type non_ref_deleter_arg1;
79 typedef typename bmupmu::if_c< bmupmu::is_lvalue_reference<D>::value
80 , D, non_ref_deleter_arg1 >::type deleter_arg_type1;
81 typedef ::boost::rv<D> & deleter_arg_type2;
82 #endif
83 };
84
85 ////////////////////////////////////////////
86 // unique_ptr_data
87 ////////////////////////////////////////////
88 template <class P, class D, bool = bmupmu::is_unary_function<D>::value || bmupmu::is_reference<D>::value >
89 struct unique_ptr_data
90 {
91 typedef typename deleter_types<D>::deleter_arg_type1 deleter_arg_type1;
92 typedef typename deleter_types<D>::del_ref del_ref;
93 typedef typename deleter_types<D>::del_cref del_cref;
94
unique_ptr_databoost::move_upd::unique_ptr_data95 unique_ptr_data() BOOST_NOEXCEPT
96 : m_p(), d()
97 {}
98
unique_ptr_databoost::move_upd::unique_ptr_data99 explicit unique_ptr_data(P p) BOOST_NOEXCEPT
100 : m_p(p), d()
101 {}
102
unique_ptr_databoost::move_upd::unique_ptr_data103 unique_ptr_data(P p, deleter_arg_type1 d1) BOOST_NOEXCEPT
104 : m_p(p), d(d1)
105 {}
106
107 template <class U>
unique_ptr_databoost::move_upd::unique_ptr_data108 unique_ptr_data(P p, BOOST_FWD_REF(U) d1) BOOST_NOEXCEPT
109 : m_p(p), d(::boost::forward<U>(d1))
110 {}
111
deleterboost::move_upd::unique_ptr_data112 del_ref deleter() { return d; }
deleterboost::move_upd::unique_ptr_data113 del_cref deleter() const{ return d; }
114
115 P m_p;
116 D d;
117
118 private:
119 unique_ptr_data& operator=(const unique_ptr_data&);
120 unique_ptr_data(const unique_ptr_data&);
121 };
122
123 template <class P, class D>
124 struct unique_ptr_data<P, D, false>
125 : private D
126 {
127 typedef typename deleter_types<D>::deleter_arg_type1 deleter_arg_type1;
128 typedef typename deleter_types<D>::del_ref del_ref;
129 typedef typename deleter_types<D>::del_cref del_cref;
130
unique_ptr_databoost::move_upd::unique_ptr_data131 unique_ptr_data() BOOST_NOEXCEPT
132 : D(), m_p()
133 {}
134
unique_ptr_databoost::move_upd::unique_ptr_data135 explicit unique_ptr_data(P p) BOOST_NOEXCEPT
136 : D(), m_p(p)
137 {}
138
unique_ptr_databoost::move_upd::unique_ptr_data139 unique_ptr_data(P p, deleter_arg_type1 d1) BOOST_NOEXCEPT
140 : D(d1), m_p(p)
141 {}
142
143 template <class U>
unique_ptr_databoost::move_upd::unique_ptr_data144 unique_ptr_data(P p, BOOST_FWD_REF(U) d) BOOST_NOEXCEPT
145 : D(::boost::forward<U>(d)), m_p(p)
146 {}
147
deleterboost::move_upd::unique_ptr_data148 del_ref deleter() BOOST_NOEXCEPT { return static_cast<del_ref>(*this); }
deleterboost::move_upd::unique_ptr_data149 del_cref deleter() const BOOST_NOEXCEPT { return static_cast<del_cref>(*this); }
150
151 P m_p;
152
153 private:
154 unique_ptr_data& operator=(const unique_ptr_data&);
155 unique_ptr_data(const unique_ptr_data&);
156 };
157
158 ////////////////////////////////////////////
159 // is_unique_ptr_convertible
160 ////////////////////////////////////////////
161
162 //Although non-standard, we avoid using pointer_traits
163 //to avoid heavy dependencies
164 template <typename T>
165 struct get_element_type
166 {
167 struct DefaultWrap { typedef bmupmu::natify<T> element_type; };
168 template <typename X> static char test(int, typename X::element_type*);
169 template <typename X> static int test(...);
170 static const bool value = (1 == sizeof(test<T>(0, 0)));
171 typedef typename bmupmu::if_c<value, T, DefaultWrap>::type::element_type type;
172 };
173
174 template<class T>
175 struct get_element_type<T*>
176 {
177 typedef T type;
178 };
179
180 template<class T>
181 struct get_cvelement
182 : bmupmu::remove_cv<typename get_element_type<T>::type>
183 {};
184
185 template <class P1, class P2>
186 struct is_same_cvelement_and_convertible
187 {
188 typedef typename bmupmu::remove_reference<P1>::type arg1;
189 typedef typename bmupmu::remove_reference<P2>::type arg2;
190 static const bool same_cvless =
191 bmupmu::is_same<typename get_cvelement<arg1>::type,typename get_cvelement<arg2>::type>::value;
192 static const bool value = same_cvless && bmupmu::is_convertible<arg1, arg2>::value;
193 };
194
195 template<bool IsArray, class FromPointer, class ThisPointer>
196 struct is_unique_ptr_convertible
197 : is_same_cvelement_and_convertible<FromPointer, ThisPointer>
198 {};
199
200 template<class FromPointer, class ThisPointer>
201 struct is_unique_ptr_convertible<false, FromPointer, ThisPointer>
202 : bmupmu::is_convertible<FromPointer, ThisPointer>
203 {};
204
205 ////////////////////////////////////////
206 //// enable_up_moveconv_assign
207 ////////////////////////////////////////
208
209 template<class T, class FromPointer, class ThisPointer, class Type = bmupmu::nat>
210 struct enable_up_ptr
211 : bmupmu::enable_if_c< is_unique_ptr_convertible
212 < bmupmu::is_array<T>::value, FromPointer, ThisPointer>::value, Type>
213 {};
214
215 ////////////////////////////////////////
216 //// enable_up_moveconv_assign
217 ////////////////////////////////////////
218
219 template<class T, class D, class U, class E>
220 struct unique_moveconvert_assignable
221 {
222 static const bool t_is_array = bmupmu::is_array<T>::value;
223 static const bool value =
224 t_is_array == bmupmu::is_array<U>::value &&
225 bmupmu::extent<T>::value == bmupmu::extent<U>::value &&
226 is_unique_ptr_convertible
227 < t_is_array
228 , typename bmupmu::pointer_type<U, E>::type, typename bmupmu::pointer_type<T, D>::type
229 >::value;
230 };
231
232 template<class T, class D, class U, class E, std::size_t N>
233 struct unique_moveconvert_assignable<T[], D, U[N], E>
234 : unique_moveconvert_assignable<T[], D, U[], E>
235 {};
236
237 template<class T, class D, class U, class E, class Type = bmupmu::nat>
238 struct enable_up_moveconv_assign
239 : bmupmu::enable_if_c<unique_moveconvert_assignable<T, D, U, E>::value, Type>
240 {};
241
242 ////////////////////////////////////////
243 //// enable_up_moveconv_constr
244 ////////////////////////////////////////
245
246 template<class D, class E, bool IsReference = bmupmu::is_reference<D>::value>
247 struct unique_deleter_is_initializable
248 : bmupmu::is_same<D, E>
249 {};
250
251 template <class T, class U>
252 class is_rvalue_convertible
253 {
254 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
255 typedef typename bmupmu::remove_reference<T>::type&& t_from;
256 #else
257 typedef typename bmupmu::if_c
258 < ::boost::has_move_emulation_enabled<T>::value && !bmupmu::is_reference<T>::value
259 , ::boost::rv<T>&
260 , typename bmupmu::add_lvalue_reference<T>::type
261 >::type t_from;
262 #endif
263
264 typedef char true_t;
265 class false_t { char dummy[2]; };
266 static false_t dispatch(...);
267 static true_t dispatch(U);
268 static t_from trigger();
269 public:
270 static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t);
271 };
272
273 template<class D, class E>
274 struct unique_deleter_is_initializable<D, E, false>
275 {
276 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
277 //Clang has some problems with is_rvalue_convertible with non-copyable types
278 //so use intrinsic if available
279 #if defined(BOOST_CLANG)
280 #if __has_feature(is_convertible_to)
281 static const bool value = __is_convertible_to(E, D);
282 #else
283 static const bool value = is_rvalue_convertible<E, D>::value;
284 #endif
285 #else
286 static const bool value = is_rvalue_convertible<E, D>::value;
287 #endif
288
289 #else //!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
290 //No hope for compilers with move emulation for now. In several compilers is_convertible
291 // leads to errors, so just move the Deleter and see if the conversion works
292 static const bool value = true; /*is_rvalue_convertible<E, D>::value*/
293 #endif
294 };
295
296 template<class T, class D, class U, class E, class Type = bmupmu::nat>
297 struct enable_up_moveconv_constr
298 : bmupmu::enable_if_c
299 < unique_moveconvert_assignable<T, D, U, E>::value && unique_deleter_is_initializable<D, E>::value
300 , Type>
301 {};
302
303 } //namespace move_upd {
304
305 namespace movelib {
306
307 //! A unique pointer is an object that owns another object and
308 //! manages that other object through a pointer.
309 //!
310 //! More precisely, a unique pointer is an object u that stores a pointer to a second object p and will dispose
311 //! of p when u is itself destroyed (e.g., when leaving block scope). In this context, u is said to own p.
312 //!
313 //! The mechanism by which u disposes of p is known as p's associated deleter, a function object whose correct
314 //! invocation results in p's appropriate disposition (typically its deletion).
315 //!
316 //! Let the notation u.p denote the pointer stored by u, and let u.d denote the associated deleter. Upon request,
317 //! u can reset (replace) u.p and u.d with another pointer and deleter, but must properly dispose of its owned
318 //! object via the associated deleter before such replacement is considered completed.
319 //!
320 //! Additionally, u can, upon request, transfer ownership to another unique pointer u2. Upon completion of
321 //! such a transfer, the following postconditions hold:
322 //! - u2.p is equal to the pre-transfer u.p,
323 //! - u.p is equal to nullptr, and
324 //! - if the pre-transfer u.d maintained state, such state has been transferred to u2.d.
325 //!
326 //! As in the case of a reset, u2 must properly dispose of its pre-transfer owned object via the pre-transfer
327 //! associated deleter before the ownership transfer is considered complete.
328 //!
329 //! Each object of a type U instantiated from the unique_ptr template specified in this subclause has the strict
330 //! ownership semantics, specified above, of a unique pointer. In partial satisfaction of these semantics, each
331 //! such U is MoveConstructible and MoveAssignable, but is not CopyConstructible nor CopyAssignable.
332 //! The template parameter T of unique_ptr may be an incomplete type.
333 //!
334 //! The uses of unique_ptr include providing exception safety for dynamically allocated memory, passing
335 //! ownership of dynamically allocated memory to a function, and returning dynamically allocated memory from
336 //! a function.
337 //!
338 //! If T is an array type (e.g. unique_ptr<MyType[]>) the interface is slightly altered:
339 //! - Pointers to types derived from T are rejected by the constructors, and by reset.
340 //! - The observers <tt>operator*</tt> and <tt>operator-></tt> are not provided.
341 //! - The indexing observer <tt>operator[]</tt> is provided.
342 //!
343 //! \tparam T Provides the type of the stored pointer.
344 //! \tparam D The deleter type:
345 //! - The default type for the template parameter D is default_delete. A client-supplied template argument
346 //! D shall be a function object type, lvalue-reference to function, or lvalue-reference to function object type
347 //! for which, given a value d of type D and a value ptr of type unique_ptr<T, D>::pointer, the expression
348 //! d(ptr) is valid and has the effect of disposing of the pointer as appropriate for that deleter.
349 //! - If the deleter's type D is not a reference type, D shall satisfy the requirements of Destructible.
350 //! - If the type <tt>remove_reference<D>::type::pointer</tt> exists, it shall satisfy the requirements of NullablePointer.
351 template <class T, class D = default_delete<T> >
352 class unique_ptr
353 {
354 #if defined(BOOST_MOVE_DOXYGEN_INVOKED)
355 public:
356 unique_ptr(const unique_ptr&) = delete;
357 unique_ptr& operator=(const unique_ptr&) = delete;
358 private:
359 #else
360 BOOST_MOVABLE_BUT_NOT_COPYABLE(unique_ptr)
361
362 typedef bmupmu::pointer_type<T, D > pointer_type_obtainer;
363 typedef bmupd::unique_ptr_data
364 <typename pointer_type_obtainer::type, D> data_type;
365 typedef typename bmupd::deleter_types<D>::deleter_arg_type1 deleter_arg_type1;
366 typedef typename bmupd::deleter_types<D>::deleter_arg_type2 deleter_arg_type2;
367 data_type m_data;
368 #endif
369
370 public:
371 //! If the type <tt>remove_reference<D>::type::pointer</tt> exists, then it shall be a
372 //! synonym for <tt>remove_reference<D>::type::pointer</tt>. Otherwise it shall be a
373 //! synonym for T*.
374 typedef typename BOOST_MOVE_SEEDOC(pointer_type_obtainer::type) pointer;
375 //! If T is an array type, then element_type is equal to T. Otherwise, if T is a type
376 //! in the form U[], element_type is equal to U.
377 typedef typename BOOST_MOVE_SEEDOC(bmupmu::remove_extent<T>::type) element_type;
378 typedef D deleter_type;
379
380 //! <b>Requires</b>: D shall satisfy the requirements of DefaultConstructible, and
381 //! that construction shall not throw an exception.
382 //!
383 //! <b>Effects</b>: Constructs a unique_ptr object that owns nothing, value-initializing the
384 //! stored pointer and the stored deleter.
385 //!
386 //! <b>Postconditions</b>: <tt>get() == nullptr</tt>. <tt>get_deleter()</tt> returns a reference to the stored deleter.
387 //!
388 //! <b>Remarks</b>: If this constructor is instantiated with a pointer type or reference type
389 //! for the template argument D, the program is ill-formed.
unique_ptr()390 BOOST_CONSTEXPR unique_ptr() BOOST_NOEXCEPT
391 : m_data()
392 {
393 //If this constructor is instantiated with a pointer type or reference type
394 //for the template argument D, the program is ill-formed.
395 BOOST_STATIC_ASSERT(!bmupmu::is_pointer<D>::value);
396 BOOST_STATIC_ASSERT(!bmupmu::is_reference<D>::value);
397 }
398
399 //! <b>Effects</b>: Same as <tt>unique_ptr()</tt> (default constructor).
400 //!
unique_ptr(BOOST_MOVE_DOC0PTR (bmupd::nullptr_type))401 BOOST_CONSTEXPR unique_ptr(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type)) BOOST_NOEXCEPT
402 : m_data()
403 {
404 //If this constructor is instantiated with a pointer type or reference type
405 //for the template argument D, the program is ill-formed.
406 BOOST_STATIC_ASSERT(!bmupmu::is_pointer<D>::value);
407 BOOST_STATIC_ASSERT(!bmupmu::is_reference<D>::value);
408 }
409
410 //! <b>Requires</b>: D shall satisfy the requirements of DefaultConstructible, and
411 //! that construction shall not throw an exception.
412 //!
413 //! <b>Effects</b>: Constructs a unique_ptr which owns p, initializing the stored pointer
414 //! with p and value initializing the stored deleter.
415 //!
416 //! <b>Postconditions</b>: <tt>get() == p</tt>. <tt>get_deleter()</tt> returns a reference to the stored deleter.
417 //!
418 //! <b>Remarks</b>: If this constructor is instantiated with a pointer type or reference type
419 //! for the template argument D, the program is ill-formed.
420 //! This constructor shall not participate in overload resolution unless:
421 //! - If T is not an array type and Pointer is implicitly convertible to pointer.
422 //! - If T is an array type and Pointer is a more CV qualified pointer to element_type.
423 template<class Pointer>
424 explicit unique_ptr(Pointer p
425 BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_ptr<T BOOST_MOVE_I Pointer BOOST_MOVE_I pointer>::type* =0)
426 ) BOOST_NOEXCEPT
427 : m_data(p)
428 {
429 //If T is not an array type, element_type_t<Pointer> derives from T
430 //it uses the default deleter and T has no virtual destructor, then you have a problem
431 BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor
432 <D, typename bmupd::get_element_type<Pointer>::type>::value ));
433 //If this constructor is instantiated with a pointer type or reference type
434 //for the template argument D, the program is ill-formed.
435 BOOST_STATIC_ASSERT(!bmupmu::is_pointer<D>::value);
436 BOOST_STATIC_ASSERT(!bmupmu::is_reference<D>::value);
437 }
438
439 //!The signature of this constructor depends upon whether D is a reference type.
440 //! - If D is non-reference type A, then the signature is <tt>unique_ptr(pointer p, const A& d)</tt>.
441 //! - If D is an lvalue-reference type A&, then the signature is <tt>unique_ptr(pointer p, A& d)</tt>.
442 //! - If D is an lvalue-reference type const A&, then the signature is <tt>unique_ptr(pointer p, const A& d)</tt>.
443 //!
444 //!
445 //! <b>Requires</b>: Either
446 //! - D is not an lvalue-reference type and d is an lvalue or const rvalue.
447 //! D shall satisfy the requirements of CopyConstructible, and the copy constructor of D
448 //! shall not throw an exception. This unique_ptr will hold a copy of d.
449 //! - D is an lvalue-reference type and d is an lvalue. the type which D references need not be CopyConstructible nor
450 //! MoveConstructible. This unique_ptr will hold a D which refers to the lvalue d.
451 //!
452 //! <b>Effects</b>: Constructs a unique_ptr object which owns p, initializing the stored pointer with p and
453 //! initializing the deleter as described above.
454 //!
455 //! <b>Postconditions</b>: <tt>get() == p</tt>. <tt>get_deleter()</tt> returns a reference to the stored deleter. If D is a
456 //! reference type then <tt>get_deleter()</tt> returns a reference to the lvalue d.
457 //!
458 //! <b>Remarks</b>: This constructor shall not participate in overload resolution unless:
459 //! - If T is not an array type and Pointer is implicitly convertible to pointer.
460 //! - If T is an array type and Pointer is a more CV qualified pointer to element_type.
461 template<class Pointer>
462 unique_ptr(Pointer p, BOOST_MOVE_SEEDOC(deleter_arg_type1) d1
463 BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_ptr<T BOOST_MOVE_I Pointer BOOST_MOVE_I pointer>::type* =0)
464 ) BOOST_NOEXCEPT
465 : m_data(p, d1)
466 {
467 //If T is not an array type, element_type_t<Pointer> derives from T
468 //it uses the default deleter and T has no virtual destructor, then you have a problem
469 BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor
470 <D, typename bmupd::get_element_type<Pointer>::type>::value ));
471 }
472
473 //! <b>Effects</b>: Same effects as <tt>template<class Pointer> unique_ptr(Pointer p, deleter_arg_type1 d1)</tt>
474 //! and additionally <tt>get() == nullptr</tt>
unique_ptr(BOOST_MOVE_DOC0PTR (bmupd::nullptr_type),BOOST_MOVE_SEEDOC (deleter_arg_type1)d1)475 unique_ptr(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type), BOOST_MOVE_SEEDOC(deleter_arg_type1) d1) BOOST_NOEXCEPT
476 : m_data(pointer(), d1)
477 {}
478
479 //! The signature of this constructor depends upon whether D is a reference type.
480 //! - If D is non-reference type A, then the signature is <tt>unique_ptr(pointer p, A&& d)</tt>.
481 //! - If D is an lvalue-reference type A&, then the signature is <tt>unique_ptr(pointer p, A&& d)</tt>.
482 //! - If D is an lvalue-reference type const A&, then the signature is <tt>unique_ptr(pointer p, const A&& d)</tt>.
483 //!
484 //! <b>Requires</b>: Either
485 //! - D is not an lvalue-reference type and d is a non-const rvalue. D
486 //! shall satisfy the requirements of MoveConstructible, and the move constructor
487 //! of D shall not throw an exception. This unique_ptr will hold a value move constructed from d.
488 //! - D is an lvalue-reference type and d is an rvalue, the program is ill-formed.
489 //!
490 //! <b>Effects</b>: Constructs a unique_ptr object which owns p, initializing the stored pointer with p and
491 //! initializing the deleter as described above.
492 //!
493 //! <b>Postconditions</b>: <tt>get() == p</tt>. <tt>get_deleter()</tt> returns a reference to the stored deleter. If D is a
494 //! reference type then <tt>get_deleter()</tt> returns a reference to the lvalue d.
495 //!
496 //! <b>Remarks</b>: This constructor shall not participate in overload resolution unless:
497 //! - If T is not an array type and Pointer is implicitly convertible to pointer.
498 //! - If T is an array type and Pointer is a more CV qualified pointer to element_type.
499 template<class Pointer>
500 unique_ptr(Pointer p, BOOST_MOVE_SEEDOC(deleter_arg_type2) d2
501 BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_ptr<T BOOST_MOVE_I Pointer BOOST_MOVE_I pointer>::type* =0)
502 ) BOOST_NOEXCEPT
503 : m_data(p, ::boost::move(d2))
504 {
505 //If T is not an array type, element_type_t<Pointer> derives from T
506 //it uses the default deleter and T has no virtual destructor, then you have a problem
507 BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor
508 <D, typename bmupd::get_element_type<Pointer>::type>::value ));
509 }
510
511 //! <b>Effects</b>: Same effects as <tt>template<class Pointer> unique_ptr(Pointer p, deleter_arg_type2 d2)</tt>
512 //! and additionally <tt>get() == nullptr</tt>
unique_ptr(BOOST_MOVE_DOC0PTR (bmupd::nullptr_type),BOOST_MOVE_SEEDOC (deleter_arg_type2)d2)513 unique_ptr(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type), BOOST_MOVE_SEEDOC(deleter_arg_type2) d2) BOOST_NOEXCEPT
514 : m_data(pointer(), ::boost::move(d2))
515 {}
516
517 //! <b>Requires</b>: If D is not a reference type, D shall satisfy the requirements of MoveConstructible.
518 //! Construction of the deleter from an rvalue of type D shall not throw an exception.
519 //!
520 //! <b>Effects</b>: Constructs a unique_ptr by transferring ownership from u to *this. If D is a reference type,
521 //! this deleter is copy constructed from u's deleter; otherwise, this deleter is move constructed from u's
522 //! deleter.
523 //!
524 //! <b>Postconditions</b>: <tt>get()</tt> yields the value u.get() yielded before the construction. <tt>get_deleter()</tt>
525 //! returns a reference to the stored deleter that was constructed from u.get_deleter(). If D is a
526 //! reference type then <tt>get_deleter()</tt> and <tt>u.get_deleter()</tt> both reference the same lvalue deleter.
unique_ptr(BOOST_RV_REF (unique_ptr)u)527 unique_ptr(BOOST_RV_REF(unique_ptr) u) BOOST_NOEXCEPT
528 : m_data(u.release(), ::boost::move_if_not_lvalue_reference<D>(u.get_deleter()))
529 {}
530
531 //! <b>Requires</b>: If E is not a reference type, construction of the deleter from an rvalue of type E shall be
532 //! well formed and shall not throw an exception. Otherwise, E is a reference type and construction of the
533 //! deleter from an lvalue of type E shall be well formed and shall not throw an exception.
534 //!
535 //! <b>Remarks</b>: This constructor shall not participate in overload resolution unless:
536 //! - <tt>unique_ptr<U, E>::pointer</tt> is implicitly convertible to pointer,
537 //! - U is not an array type, and
538 //! - either D is a reference type and E is the same type as D, or D is not a reference type and E is
539 //! implicitly convertible to D.
540 //!
541 //! <b>Effects</b>: Constructs a unique_ptr by transferring ownership from u to *this. If E is a reference type,
542 //! this deleter is copy constructed from u's deleter; otherwise, this deleter is move constructed from u's deleter.
543 //!
544 //! <b>Postconditions</b>: <tt>get()</tt> yields the value <tt>u.get()</tt> yielded before the construction. <tt>get_deleter()</tt>
545 //! returns a reference to the stored deleter that was constructed from <tt>u.get_deleter()</tt>.
546 template <class U, class E>
547 unique_ptr( BOOST_RV_REF_BEG_IF_CXX11 unique_ptr<U, E> BOOST_RV_REF_END_IF_CXX11 u
548 BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_moveconv_constr<T BOOST_MOVE_I D BOOST_MOVE_I U BOOST_MOVE_I E>::type* =0)
549 ) BOOST_NOEXCEPT
550 : m_data(u.release(), ::boost::move_if_not_lvalue_reference<E>(u.get_deleter()))
551 {
552 //If T is not an array type, U derives from T
553 //it uses the default deleter and T has no virtual destructor, then you have a problem
554 BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor
555 <D, typename unique_ptr<U, E>::pointer>::value ));
556 }
557
558 //! <b>Requires</b>: The expression <tt>get_deleter()(get())</tt> shall be well formed, shall have well-defined behavior,
559 //! and shall not throw exceptions.
560 //!
561 //! <b>Effects</b>: If <tt>get() == nullpt1r</tt> there are no effects. Otherwise <tt>get_deleter()(get())</tt>.
562 //!
563 //! <b>Note</b>: The use of default_delete requires T to be a complete type
~unique_ptr()564 ~unique_ptr()
565 { if(m_data.m_p) m_data.deleter()(m_data.m_p); }
566
567 //! <b>Requires</b>: If D is not a reference type, D shall satisfy the requirements of MoveAssignable
568 //! and assignment of the deleter from an rvalue of type D shall not throw an exception. Otherwise, D
569 //! is a reference type; <tt>remove_reference<D>::type</tt> shall satisfy the CopyAssignable requirements and
570 //! assignment of the deleter from an lvalue of type D shall not throw an exception.
571 //!
572 //! <b>Effects</b>: Transfers ownership from u to *this as if by calling <tt>reset(u.release())</tt> followed
573 //! by <tt>get_deleter() = std::forward<D>(u.get_deleter())</tt>.
574 //!
575 //! <b>Returns</b>: *this.
operator =(BOOST_RV_REF (unique_ptr)u)576 unique_ptr& operator=(BOOST_RV_REF(unique_ptr) u) BOOST_NOEXCEPT
577 {
578 this->reset(u.release());
579 m_data.deleter() = ::boost::move_if_not_lvalue_reference<D>(u.get_deleter());
580 return *this;
581 }
582
583 //! <b>Requires</b>: If E is not a reference type, assignment of the deleter from an rvalue of type E shall be
584 //! well-formed and shall not throw an exception. Otherwise, E is a reference type and assignment of the
585 //! deleter from an lvalue of type E shall be well-formed and shall not throw an exception.
586 //!
587 //! <b>Remarks</b>: This operator shall not participate in overload resolution unless:
588 //! - <tt>unique_ptr<U, E>::pointer</tt> is implicitly convertible to pointer and
589 //! - U is not an array type.
590 //!
591 //! <b>Effects</b>: Transfers ownership from u to *this as if by calling <tt>reset(u.release())</tt> followed by
592 //! <tt>get_deleter() = std::forward<E>(u.get_deleter())</tt>.
593 //!
594 //! <b>Returns</b>: *this.
595 template <class U, class E>
BOOST_MOVE_DOC1ST(unique_ptr &,typename bmupd::enable_up_moveconv_assign<T BOOST_MOVE_I D BOOST_MOVE_I U BOOST_MOVE_I E BOOST_MOVE_I unique_ptr &>::type)596 BOOST_MOVE_DOC1ST(unique_ptr&, typename bmupd::enable_up_moveconv_assign
597 <T BOOST_MOVE_I D BOOST_MOVE_I U BOOST_MOVE_I E BOOST_MOVE_I unique_ptr &>::type)
598 operator=(BOOST_RV_REF_BEG unique_ptr<U, E> BOOST_RV_REF_END u) BOOST_NOEXCEPT
599 {
600 this->reset(u.release());
601 m_data.deleter() = ::boost::move_if_not_lvalue_reference<E>(u.get_deleter());
602 return *this;
603 }
604
605 //! <b>Effects</b>: <tt>reset()</tt>.
606 //!
607 //! <b>Postcondition</b>: <tt>get() == nullptr</tt>
608 //!
609 //! <b>Returns</b>: *this.
operator =(BOOST_MOVE_DOC0PTR (bmupd::nullptr_type))610 unique_ptr& operator=(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type)) BOOST_NOEXCEPT
611 { this->reset(); return *this; }
612
613 //! <b>Requires</b>: <tt>get() != nullptr</tt>.
614 //!
615 //! <b>Returns</b>: <tt>*get()</tt>.
616 //!
617 //! <b>Remarks</b: If T is an array type, the program is ill-formed.
BOOST_MOVE_DOC1ST(element_type &,typename bmupmu::add_lvalue_reference<element_type>::type)618 BOOST_MOVE_DOC1ST(element_type&, typename bmupmu::add_lvalue_reference<element_type>::type)
619 operator*() const BOOST_NOEXCEPT
620 {
621 BOOST_STATIC_ASSERT((!bmupmu::is_array<T>::value));
622 return *m_data.m_p;
623 }
624
625 //! <b>Requires</b>: i < the number of elements in the array to which the stored pointer points.
626 //!
627 //! <b>Returns</b>: <tt>get()[i]</tt>.
628 //!
629 //! <b>Remarks</b: If T is not an array type, the program is ill-formed.
BOOST_MOVE_DOC1ST(element_type &,typename bmupmu::add_lvalue_reference<element_type>::type)630 BOOST_MOVE_DOC1ST(element_type&, typename bmupmu::add_lvalue_reference<element_type>::type)
631 operator[](std::size_t i) const BOOST_NOEXCEPT
632 {
633 BOOST_ASSERT( bmupmu::extent<T>::value == 0 || i < bmupmu::extent<T>::value );
634 BOOST_ASSERT(m_data.m_p);
635 return m_data.m_p[i];
636 }
637
638 //! <b>Requires</b>: <tt>get() != nullptr</tt>.
639 //!
640 //! <b>Returns</b>: <tt>get()</tt>.
641 //!
642 //! <b>Note</b>: use typically requires that T be a complete type.
643 //!
644 //! <b>Remarks</b: If T is an array type, the program is ill-formed.
operator ->() const645 pointer operator->() const BOOST_NOEXCEPT
646 {
647 BOOST_STATIC_ASSERT((!bmupmu::is_array<T>::value));
648 BOOST_ASSERT(m_data.m_p);
649 return m_data.m_p;
650 }
651
652 //! <b>Returns</b>: The stored pointer.
653 //!
get() const654 pointer get() const BOOST_NOEXCEPT
655 { return m_data.m_p; }
656
657 //! <b>Returns</b>: A reference to the stored deleter.
658 //!
BOOST_MOVE_DOC1ST(D &,typename bmupmu::add_lvalue_reference<D>::type)659 BOOST_MOVE_DOC1ST(D&, typename bmupmu::add_lvalue_reference<D>::type)
660 get_deleter() BOOST_NOEXCEPT
661 { return m_data.deleter(); }
662
663 //! <b>Returns</b>: A reference to the stored deleter.
664 //!
BOOST_MOVE_DOC1ST(const D &,typename bmupmu::add_const_lvalue_reference<D>::type)665 BOOST_MOVE_DOC1ST(const D&, typename bmupmu::add_const_lvalue_reference<D>::type)
666 get_deleter() const BOOST_NOEXCEPT
667 { return m_data.deleter(); }
668
669 #ifdef BOOST_MOVE_DOXYGEN_INVOKED
670 //! <b>Returns</b>: Returns: get() != nullptr.
671 //!
operator bool() const672 explicit operator bool
673 #else
674 operator bmupd::explicit_bool_arg
675 #endif
676 ()const BOOST_NOEXCEPT
677 {
678 return m_data.m_p
679 ? &bmupd::bool_conversion::for_bool
680 : bmupd::explicit_bool_arg(0);
681 }
682
683 //! <b>Postcondition</b>: <tt>get() == nullptr</tt>.
684 //!
685 //! <b>Returns</b>: The value <tt>get()</tt> had at the start of the call to release.
release()686 pointer release() BOOST_NOEXCEPT
687 {
688 const pointer tmp = m_data.m_p;
689 m_data.m_p = pointer();
690 return tmp;
691 }
692
693 //! <b>Requires</b>: The expression <tt>get_deleter()(get())</tt> shall be well formed, shall have well-defined behavior,
694 //! and shall not throw exceptions.
695 //!
696 //! <b>Effects</b>: assigns p to the stored pointer, and then if the old value of the stored pointer, old_p, was not
697 //! equal to nullptr, calls <tt>get_deleter()(old_p)</tt>. Note: The order of these operations is significant
698 //! because the call to <tt>get_deleter()</tt> may destroy *this.
699 //!
700 //! <b>Postconditions</b>: <tt>get() == p</tt>. Note: The postcondition does not hold if the call to <tt>get_deleter()</tt>
701 //! destroys *this since <tt>this->get()</tt> is no longer a valid expression.
702 //!
703 //! <b>Remarks</b>: This constructor shall not participate in overload resolution unless:
704 //! - If T is not an array type and Pointer is implicitly convertible to pointer.
705 //! - If T is an array type and Pointer is a more CV qualified pointer to element_type.
706 template<class Pointer>
BOOST_MOVE_DOC1ST(void,typename bmupd::enable_up_ptr<T BOOST_MOVE_I Pointer BOOST_MOVE_I pointer BOOST_MOVE_I void>::type)707 BOOST_MOVE_DOC1ST(void, typename bmupd::enable_up_ptr<T BOOST_MOVE_I Pointer BOOST_MOVE_I pointer BOOST_MOVE_I void>::type)
708 reset(Pointer p) BOOST_NOEXCEPT
709 {
710 //If T is not an array type, element_type_t<Pointer> derives from T
711 //it uses the default deleter and T has no virtual destructor, then you have a problem
712 BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor
713 <D, typename bmupd::get_element_type<Pointer>::type>::value ));
714 pointer tmp = m_data.m_p;
715 m_data.m_p = p;
716 if(tmp) m_data.deleter()(tmp);
717 }
718
719 //! <b>Requires</b>: The expression <tt>get_deleter()(get())</tt> shall be well formed, shall have well-defined behavior,
720 //! and shall not throw exceptions.
721 //!
722 //! <b>Effects</b>: assigns nullptr to the stored pointer, and then if the old value of the stored pointer, old_p, was not
723 //! equal to nullptr, calls <tt>get_deleter()(old_p)</tt>. Note: The order of these operations is significant
724 //! because the call to <tt>get_deleter()</tt> may destroy *this.
725 //!
726 //! <b>Postconditions</b>: <tt>get() == p</tt>. Note: The postcondition does not hold if the call to <tt>get_deleter()</tt>
727 //! destroys *this since <tt>this->get()</tt> is no longer a valid expression.
reset()728 void reset() BOOST_NOEXCEPT
729 { this->reset(pointer()); }
730
731 //! <b>Effects</b>: Same as <tt>reset()</tt>
732 //!
reset(BOOST_MOVE_DOC0PTR (bmupd::nullptr_type))733 void reset(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type)) BOOST_NOEXCEPT
734 { this->reset(); }
735
736 //! <b>Requires</b>: <tt>get_deleter()</tt> shall be swappable and shall not throw an exception under swap.
737 //!
738 //! <b>Effects</b>: Invokes swap on the stored pointers and on the stored deleters of *this and u.
swap(unique_ptr & u)739 void swap(unique_ptr& u) BOOST_NOEXCEPT
740 {
741 ::boost::adl_move_swap(m_data.m_p, u.m_data.m_p);
742 ::boost::adl_move_swap(m_data.deleter(), u.m_data.deleter());
743 }
744 };
745
746 //! <b>Effects</b>: Calls <tt>x.swap(y)</tt>.
747 //!
748 template <class T, class D>
swap(unique_ptr<T,D> & x,unique_ptr<T,D> & y)749 inline void swap(unique_ptr<T, D> &x, unique_ptr<T, D> &y) BOOST_NOEXCEPT
750 { x.swap(y); }
751
752 //! <b>Returns</b>: <tt>x.get() == y.get()</tt>.
753 //!
754 template <class T1, class D1, class T2, class D2>
operator ==(const unique_ptr<T1,D1> & x,const unique_ptr<T2,D2> & y)755 inline bool operator==(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
756 { return x.get() == y.get(); }
757
758 //! <b>Returns</b>: <tt>x.get() != y.get()</tt>.
759 //!
760 template <class T1, class D1, class T2, class D2>
operator !=(const unique_ptr<T1,D1> & x,const unique_ptr<T2,D2> & y)761 inline bool operator!=(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
762 { return x.get() != y.get(); }
763
764 //! <b>Returns</b>: x.get() < y.get().
765 //!
766 //! <b>Remarks</b>: This comparison shall induce a
767 //! strict weak ordering betwen pointers.
768 template <class T1, class D1, class T2, class D2>
operator <(const unique_ptr<T1,D1> & x,const unique_ptr<T2,D2> & y)769 inline bool operator<(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
770 { return x.get() < y.get(); }
771
772 //! <b>Returns</b>: !(y < x).
773 //!
774 template <class T1, class D1, class T2, class D2>
operator <=(const unique_ptr<T1,D1> & x,const unique_ptr<T2,D2> & y)775 inline bool operator<=(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
776 { return !(y < x); }
777
778 //! <b>Returns</b>: y < x.
779 //!
780 template <class T1, class D1, class T2, class D2>
operator >(const unique_ptr<T1,D1> & x,const unique_ptr<T2,D2> & y)781 inline bool operator>(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
782 { return y < x; }
783
784 //! <b>Returns</b>:!(x < y).
785 //!
786 template <class T1, class D1, class T2, class D2>
operator >=(const unique_ptr<T1,D1> & x,const unique_ptr<T2,D2> & y)787 inline bool operator>=(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
788 { return !(x < y); }
789
790 //! <b>Returns</b>:!x.
791 //!
792 template <class T, class D>
operator ==(const unique_ptr<T,D> & x,BOOST_MOVE_DOC0PTR (bmupd::nullptr_type))793 inline bool operator==(const unique_ptr<T, D> &x, BOOST_MOVE_DOC0PTR(bmupd::nullptr_type)) BOOST_NOEXCEPT
794 { return !x; }
795
796 //! <b>Returns</b>:!x.
797 //!
798 template <class T, class D>
operator ==(BOOST_MOVE_DOC0PTR (bmupd::nullptr_type),const unique_ptr<T,D> & x)799 inline bool operator==(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type), const unique_ptr<T, D> &x) BOOST_NOEXCEPT
800 { return !x; }
801
802 //! <b>Returns</b>: (bool)x.
803 //!
804 template <class T, class D>
operator !=(const unique_ptr<T,D> & x,BOOST_MOVE_DOC0PTR (bmupd::nullptr_type))805 inline bool operator!=(const unique_ptr<T, D> &x, BOOST_MOVE_DOC0PTR(bmupd::nullptr_type)) BOOST_NOEXCEPT
806 { return !!x; }
807
808 //! <b>Returns</b>: (bool)x.
809 //!
810 template <class T, class D>
operator !=(BOOST_MOVE_DOC0PTR (bmupd::nullptr_type),const unique_ptr<T,D> & x)811 inline bool operator!=(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type), const unique_ptr<T, D> &x) BOOST_NOEXCEPT
812 { return !!x; }
813
814 //! <b>Requires</b>: <tt>operator </tt> shall induce a strict weak ordering on unique_ptr<T, D>::pointer values.
815 //!
816 //! <b>Returns</b>: Returns <tt>x.get() < pointer()</tt>.
817 template <class T, class D>
operator <(const unique_ptr<T,D> & x,BOOST_MOVE_DOC0PTR (bmupd::nullptr_type))818 inline bool operator<(const unique_ptr<T, D> &x, BOOST_MOVE_DOC0PTR(bmupd::nullptr_type))
819 { return x.get() < typename unique_ptr<T, D>::pointer(); }
820
821 //! <b>Requires</b>: <tt>operator </tt> shall induce a strict weak ordering on unique_ptr<T, D>::pointer values.
822 //!
823 //! <b>Returns</b>: Returns <tt>pointer() < x.get()</tt>.
824 template <class T, class D>
operator <(BOOST_MOVE_DOC0PTR (bmupd::nullptr_type),const unique_ptr<T,D> & x)825 inline bool operator<(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type), const unique_ptr<T, D> &x)
826 { return typename unique_ptr<T, D>::pointer() < x.get(); }
827
828 //! <b>Returns</b>: <tt>nullptr < x</tt>.
829 //!
830 template <class T, class D>
operator >(const unique_ptr<T,D> & x,BOOST_MOVE_DOC0PTR (bmupd::nullptr_type))831 inline bool operator>(const unique_ptr<T, D> &x, BOOST_MOVE_DOC0PTR(bmupd::nullptr_type))
832 { return x.get() > typename unique_ptr<T, D>::pointer(); }
833
834 //! <b>Returns</b>: <tt>x < nullptr</tt>.
835 //!
836 template <class T, class D>
operator >(BOOST_MOVE_DOC0PTR (bmupd::nullptr_type),const unique_ptr<T,D> & x)837 inline bool operator>(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type), const unique_ptr<T, D> &x)
838 { return typename unique_ptr<T, D>::pointer() > x.get(); }
839
840 //! <b>Returns</b>: <tt>!(nullptr < x)</tt>.
841 //!
842 template <class T, class D>
operator <=(const unique_ptr<T,D> & x,BOOST_MOVE_DOC0PTR (bmupd::nullptr_type))843 inline bool operator<=(const unique_ptr<T, D> &x, BOOST_MOVE_DOC0PTR(bmupd::nullptr_type))
844 { return !(bmupd::nullptr_type() < x); }
845
846 //! <b>Returns</b>: <tt>!(x < nullptr)</tt>.
847 //!
848 template <class T, class D>
operator <=(BOOST_MOVE_DOC0PTR (bmupd::nullptr_type),const unique_ptr<T,D> & x)849 inline bool operator<=(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type), const unique_ptr<T, D> &x)
850 { return !(x < bmupd::nullptr_type()); }
851
852 //! <b>Returns</b>: <tt>!(x < nullptr)</tt>.
853 //!
854 template <class T, class D>
operator >=(const unique_ptr<T,D> & x,BOOST_MOVE_DOC0PTR (bmupd::nullptr_type))855 inline bool operator>=(const unique_ptr<T, D> &x, BOOST_MOVE_DOC0PTR(bmupd::nullptr_type))
856 { return !(x < bmupd::nullptr_type()); }
857
858 //! <b>Returns</b>: <tt>!(nullptr < x)</tt>.
859 //!
860 template <class T, class D>
operator >=(BOOST_MOVE_DOC0PTR (bmupd::nullptr_type),const unique_ptr<T,D> & x)861 inline bool operator>=(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type), const unique_ptr<T, D> &x)
862 { return !(bmupd::nullptr_type() < x); }
863
864 } //namespace movelib {
865 } //namespace boost{
866
867 #include <boost/move/detail/config_end.hpp>
868
869 #endif //#ifndef BOOST_MOVE_UNIQUE_PTR_HPP_INCLUDED
870