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_DEFAULT_DELETE_HPP_INCLUDED
12 #define BOOST_MOVE_DEFAULT_DELETE_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/utility_core.hpp>
26 #include <boost/static_assert.hpp>
27 
28 #include <cstddef>   //For std::size_t,std::nullptr_t
29 
30 //!\file
31 //! Describes the default deleter (destruction policy) of <tt>unique_ptr</tt>: <tt>default_delete</tt>.
32 
33 namespace boost{
34 // @cond
35 namespace move_upd {
36 
37 namespace bmupmu = ::boost::move_upmu;
38 
39 ////////////////////////////////////////
40 ////        enable_def_del
41 ////////////////////////////////////////
42 
43 //compatible with a pointer type T*:
44 //When either Y* is convertible to T*
45 //Y is U[N] and T is U cv []
46 template<class U, class T>
47 struct def_del_compatible_cond
48    : bmupmu::is_convertible<U*, T*>
49 {};
50 
51 template<class U, class T, std::size_t N>
52 struct def_del_compatible_cond<U[N], T[]>
53    : def_del_compatible_cond<U[], T[]>
54 {};
55 
56 template<class U, class T, class Type = bmupmu::nat>
57 struct enable_def_del
58    : bmupmu::enable_if_c<def_del_compatible_cond<U, T>::value, Type>
59 {};
60 
61 ////////////////////////////////////////
62 ////        enable_defdel_call
63 ////////////////////////////////////////
64 
65 //When 2nd is T[N], 1st(*)[N] shall be convertible to T(*)[N];
66 //When 2nd is T[],  1st(*)[] shall be convertible to T(*)[];
67 //Otherwise, 1st* shall be convertible to 2nd*.
68 
69 template<class U, class T, class Type = bmupmu::nat>
70 struct enable_defdel_call
71    : public enable_def_del<U, T, Type>
72 {};
73 
74 template<class U, class T, class Type>
75 struct enable_defdel_call<U, T[], Type>
76    : public enable_def_del<U[], T[], Type>
77 {};
78 
79 template<class U, class T, class Type, std::size_t N>
80 struct enable_defdel_call<U, T[N], Type>
81    : public enable_def_del<U[N], T[N], Type>
82 {};
83 
84 ////////////////////////////////////////
85 ////     Some bool literal zero conversion utilities
86 ////////////////////////////////////////
87 
88 struct bool_conversion {int for_bool; int for_arg(); };
89 typedef int bool_conversion::* explicit_bool_arg;
90 
91 #if !defined(BOOST_NO_CXX11_NULLPTR) && !defined(BOOST_NO_CXX11_DECLTYPE)
92    typedef decltype(nullptr) nullptr_type;
93 #elif !defined(BOOST_NO_CXX11_NULLPTR)
94    typedef std::nullptr_t nullptr_type;
95 #else
96    typedef int (bool_conversion::*nullptr_type)();
97 #endif
98 
99 template<bool B>
100 struct is_array_del
101 {};
102 
103 template<class T>
call_delete(T * p,is_array_del<true>)104 void call_delete(T *p, is_array_del<true>)
105 {
106    delete [] p;
107 }
108 
109 template<class T>
call_delete(T * p,is_array_del<false>)110 void call_delete(T *p, is_array_del<false>)
111 {
112    delete p;
113 }
114 
115 template< class T, class U
116         , bool enable =  def_del_compatible_cond< U, T>::value &&
117                         !move_upmu::is_array<T>::value &&
118                         !move_upmu::is_same<typename move_upmu::remove_cv<T>::type, void>::value &&
119                         !move_upmu::is_same<typename move_upmu::remove_cv<U>::type, typename move_upmu::remove_cv<T>::type>::value
120         >
121 struct missing_virtual_destructor_default_delete
122 {  static const bool value = !move_upmu::has_virtual_destructor<T>::value;  };
123 
124 template<class T, class U>
125 struct missing_virtual_destructor_default_delete<T, U, false>
126 {  static const bool value = false;  };
127 
128 //////////////////////////////////////
129 //       missing_virtual_destructor
130 //////////////////////////////////////
131 
132 template<class Deleter, class U>
133 struct missing_virtual_destructor
134 {  static const bool value = false;  };
135 
136 template<class T, class U>
137 struct missing_virtual_destructor< ::boost::movelib::default_delete<T>, U >
138    : missing_virtual_destructor_default_delete<T, U>
139 {};
140 
141 
142 }  //namespace move_upd {
143 // @endcond
144 
145 namespace movelib {
146 
147 namespace bmupd = boost::move_upd;
148 namespace bmupmu = ::boost::move_upmu;
149 
150 //!The class template <tt>default_delete</tt> serves as the default deleter
151 //!(destruction policy) for the class template <tt>unique_ptr</tt>.
152 //!
153 //! \tparam T The type to be deleted. It may be an incomplete type
154 template <class T>
155 struct default_delete
156 {
157    //! Default constructor.
158    //!
159    BOOST_CONSTEXPR default_delete()
160    //Avoid "defaulted on its first declaration must not have an exception-specification" error for GCC 4.6
161    #if !defined(BOOST_GCC) || (BOOST_GCC < 40600 && BOOST_GCC >= 40700) || defined(BOOST_MOVE_DOXYGEN_INVOKED)
162    BOOST_NOEXCEPT
163    #endif
164    #if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || defined(BOOST_MOVE_DOXYGEN_INVOKED)
165    = default;
166    #else
167    {};
168    #endif
169 
170    #if defined(BOOST_MOVE_DOXYGEN_INVOKED)
171    //! Trivial copy constructor
172    //!
173    default_delete(const default_delete&) BOOST_NOEXCEPT = default;
174    //! Trivial assignment
175    //!
176    default_delete &operator=(const default_delete&) BOOST_NOEXCEPT = default;
177    #else
178    typedef typename bmupmu::remove_extent<T>::type element_type;
179    #endif
180 
181    //! <b>Effects</b>: Constructs a default_delete object from another <tt>default_delete<U></tt> object.
182    //!
183    //! <b>Remarks</b>: This constructor shall not participate in overload resolution unless:
184    //!   - If T is not an array type and U* is implicitly convertible to T*.
185    //!   - If T is an array type and U* is a more CV qualified pointer to remove_extent<T>::type.
186    template <class U>
187    default_delete(const default_delete<U>&
188       BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_def_del<U BOOST_MOVE_I T>::type* =0)
189       ) BOOST_NOEXCEPT
190    {
191       //If T is not an array type, U derives from T
192       //and T has no virtual destructor, then you have a problem
193       BOOST_STATIC_ASSERT(( !bmupd::missing_virtual_destructor<default_delete, U>::value ));
194    }
195 
196    //! <b>Effects</b>: Constructs a default_delete object from another <tt>default_delete<U></tt> object.
197    //!
198    //! <b>Remarks</b>: This constructor shall not participate in overload resolution unless:
199    //!   - If T is not an array type and U* is implicitly convertible to T*.
200    //!   - If T is an array type and U* is a more CV qualified pointer to remove_extent<T>::type.
201    template <class U>
BOOST_MOVE_DOC1STboost::movelib::default_delete202    BOOST_MOVE_DOC1ST(default_delete&,
203       typename bmupd::enable_def_del<U BOOST_MOVE_I T BOOST_MOVE_I default_delete &>::type)
204       operator=(const default_delete<U>&) BOOST_NOEXCEPT
205    {
206       //If T is not an array type, U derives from T
207       //and T has no virtual destructor, then you have a problem
208       BOOST_STATIC_ASSERT(( !bmupd::missing_virtual_destructor<default_delete, U>::value ));
209       return *this;
210    }
211 
212    //! <b>Effects</b>: if T is not an array type, calls <tt>delete</tt> on static_cast<T*>(ptr),
213    //!   otherwise calls <tt>delete[]</tt> on static_cast<remove_extent<T>::type*>(ptr).
214    //!
215    //! <b>Remarks</b>: If U is an incomplete type, the program is ill-formed.
216    //!   This operator shall not participate in overload resolution unless:
217    //!      - T is not an array type and U* is convertible to T*, OR
218    //!      - T is an array type, and remove_cv<U>::type is the same type as
219    //!         remove_cv<remove_extent<T>::type>::type and U* is convertible to remove_extent<T>::type*.
220    template <class U>
BOOST_MOVE_DOC1STboost::movelib::default_delete221    BOOST_MOVE_DOC1ST(void, typename bmupd::enable_defdel_call<U BOOST_MOVE_I T BOOST_MOVE_I void>::type)
222       operator()(U* ptr) const BOOST_NOEXCEPT
223    {
224       //U must be a complete type
225       BOOST_STATIC_ASSERT(sizeof(U) > 0);
226       //If T is not an array type, U derives from T
227       //and T has no virtual destructor, then you have a problem
228       BOOST_STATIC_ASSERT(( !bmupd::missing_virtual_destructor<default_delete, U>::value ));
229       element_type * const p = static_cast<element_type*>(ptr);
230       move_upd::call_delete(p, move_upd::is_array_del<bmupmu::is_array<T>::value>());
231    }
232 
233    //! <b>Effects</b>: Same as <tt>(*this)(static_cast<element_type*>(nullptr))</tt>.
234    //!
operator ()boost::movelib::default_delete235    void operator()(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type)) const BOOST_NOEXCEPT
236    {  BOOST_STATIC_ASSERT(sizeof(element_type) > 0);  }
237 };
238 
239 }  //namespace movelib {
240 }  //namespace boost{
241 
242 #include <boost/move/detail/config_end.hpp>
243 
244 #endif   //#ifndef BOOST_MOVE_DEFAULT_DELETE_HPP_INCLUDED
245