mirror of
https://github.com/boostorg/move.git
synced 2025-08-02 13:44:28 +02:00
Added check for types with no virtual destructor when using default_delete and non-array types
This commit is contained in:
@@ -128,7 +128,11 @@ struct default_delete
|
|||||||
default_delete(const default_delete<U>&
|
default_delete(const default_delete<U>&
|
||||||
BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_def_del<U BOOST_MOVE_I T>::type* =0)
|
BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_def_del<U BOOST_MOVE_I T>::type* =0)
|
||||||
) BOOST_NOEXCEPT
|
) BOOST_NOEXCEPT
|
||||||
{}
|
{
|
||||||
|
//If T is not an array type, U derives from T
|
||||||
|
//and T has no virtual destructor, then you have a problem
|
||||||
|
BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor<default_delete, U>::value ));
|
||||||
|
}
|
||||||
|
|
||||||
//! <b>Effects</b>: Constructs a default_delete object from another <tt>default_delete<U></tt> object.
|
//! <b>Effects</b>: Constructs a default_delete object from another <tt>default_delete<U></tt> object.
|
||||||
//!
|
//!
|
||||||
@@ -139,7 +143,12 @@ struct default_delete
|
|||||||
BOOST_MOVE_DOC1ST(default_delete&,
|
BOOST_MOVE_DOC1ST(default_delete&,
|
||||||
typename bmupd::enable_def_del<U BOOST_MOVE_I T BOOST_MOVE_I default_delete &>::type)
|
typename bmupd::enable_def_del<U BOOST_MOVE_I T BOOST_MOVE_I default_delete &>::type)
|
||||||
operator=(const default_delete<U>&) BOOST_NOEXCEPT
|
operator=(const default_delete<U>&) BOOST_NOEXCEPT
|
||||||
{ return *this; }
|
{
|
||||||
|
//If T is not an array type, U derives from T
|
||||||
|
//and T has no virtual destructor, then you have a problem
|
||||||
|
BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor<default_delete, U>::value ));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
//! <b>Effects</b>: if T is not an array type, calls <tt>delete</tt> on static_cast<T*>(ptr),
|
//! <b>Effects</b>: if T is not an array type, calls <tt>delete</tt> on static_cast<T*>(ptr),
|
||||||
//! otherwise calls <tt>delete[]</tt> on static_cast<remove_extent<T>::type*>(ptr).
|
//! otherwise calls <tt>delete[]</tt> on static_cast<remove_extent<T>::type*>(ptr).
|
||||||
@@ -155,6 +164,9 @@ struct default_delete
|
|||||||
{
|
{
|
||||||
//U must be a complete type
|
//U must be a complete type
|
||||||
BOOST_STATIC_ASSERT(sizeof(U) > 0);
|
BOOST_STATIC_ASSERT(sizeof(U) > 0);
|
||||||
|
//If T is not an array type, U derives from T
|
||||||
|
//and T has no virtual destructor, then you have a problem
|
||||||
|
BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor<default_delete, U>::value ));
|
||||||
element_type * const p = static_cast<element_type*>(ptr);
|
element_type * const p = static_cast<element_type*>(ptr);
|
||||||
bmupmu::is_array<T>::value ? delete [] p : delete p;
|
bmupmu::is_array<T>::value ? delete [] p : delete p;
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,13 @@
|
|||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
|
namespace movelib {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct default_delete;
|
||||||
|
|
||||||
|
} //namespace movelib {
|
||||||
|
|
||||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||||
//Forward declare boost::rv
|
//Forward declare boost::rv
|
||||||
template <class T> class rv;
|
template <class T> class rv;
|
||||||
@@ -423,7 +430,7 @@ class is_convertible
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
// is_unary_function
|
// is_unary_function
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
#if defined(BOOST_MSVC) || defined(__BORLANDC_)
|
#if defined(BOOST_MSVC) || defined(__BORLANDC_)
|
||||||
#define BOOST_MOVE_TT_DECL __cdecl
|
#define BOOST_MOVE_TT_DECL __cdecl
|
||||||
@@ -517,6 +524,66 @@ template<typename T>
|
|||||||
struct is_unary_function
|
struct is_unary_function
|
||||||
{ static const bool value = is_unary_function_impl<T>::value; };
|
{ static const bool value = is_unary_function_impl<T>::value; };
|
||||||
|
|
||||||
|
//////////////////////////////////////
|
||||||
|
// has_virtual_destructor
|
||||||
|
//////////////////////////////////////
|
||||||
|
#if (defined(BOOST_MSVC) && defined(BOOST_MSVC_FULL_VER) && (BOOST_MSVC_FULL_VER >=140050215))\
|
||||||
|
|| (defined(BOOST_INTEL) && defined(_MSC_VER) && (_MSC_VER >= 1500))
|
||||||
|
# define BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T) __has_virtual_destructor(T)
|
||||||
|
#elif defined(BOOST_CLANG) && defined(__has_feature)
|
||||||
|
# if __has_feature(has_virtual_destructor)
|
||||||
|
# define BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T) __has_virtual_destructor(T)
|
||||||
|
# endif
|
||||||
|
#elif defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3) && !defined(__GCCXML__))) && !defined(BOOST_CLANG)
|
||||||
|
# define BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T) __has_virtual_destructor(T)
|
||||||
|
#elif defined(__ghs__) && (__GHS_VERSION_NUMBER >= 600)
|
||||||
|
# define BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T) __has_virtual_destructor(T)
|
||||||
|
#elif defined(__CODEGEARC__)
|
||||||
|
# define BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T) __has_virtual_destructor(T)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR
|
||||||
|
template<class T>
|
||||||
|
struct has_virtual_destructor{ static const bool value = BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T); };
|
||||||
|
#else
|
||||||
|
//If no intrinsic is available you trust the programmer knows what is doing
|
||||||
|
template<class T>
|
||||||
|
struct has_virtual_destructor{ static const bool value = true; };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////
|
||||||
|
// missing_virtual_destructor
|
||||||
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
template< class T, class U
|
||||||
|
, bool enable = is_convertible< typename remove_cv<U>::type*
|
||||||
|
, typename remove_cv<T>::type*>::value &&
|
||||||
|
!is_array<T>::value &&
|
||||||
|
!is_same<typename remove_cv<T>::type, void>::value &&
|
||||||
|
!is_same<typename remove_cv<U>::type, typename remove_cv<T>::type>::value
|
||||||
|
>
|
||||||
|
struct missing_virtual_destructor_default_delete
|
||||||
|
{
|
||||||
|
static const bool value = !has_virtual_destructor<T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
struct missing_virtual_destructor_default_delete<T, U, false>
|
||||||
|
{
|
||||||
|
static const bool value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Deleter, class U>
|
||||||
|
struct missing_virtual_destructor
|
||||||
|
{
|
||||||
|
static const bool value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
struct missing_virtual_destructor< ::boost::movelib::default_delete<T>, U >
|
||||||
|
: missing_virtual_destructor_default_delete<T, U>
|
||||||
|
{};
|
||||||
|
|
||||||
} //namespace move_upmu {
|
} //namespace move_upmu {
|
||||||
} //namespace boost {
|
} //namespace boost {
|
||||||
|
|
||||||
|
@@ -411,6 +411,10 @@ class unique_ptr
|
|||||||
) BOOST_NOEXCEPT
|
) BOOST_NOEXCEPT
|
||||||
: m_data(p)
|
: m_data(p)
|
||||||
{
|
{
|
||||||
|
//If T is not an array type, element_type_t<Pointer> derives from T
|
||||||
|
//it uses the default deleter and T has no virtual destructor, then you have a problem
|
||||||
|
BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor
|
||||||
|
<D, typename bmupd::get_element_type<Pointer>::type>::value ));
|
||||||
//If this constructor is instantiated with a pointer type or reference type
|
//If this constructor is instantiated with a pointer type or reference type
|
||||||
//for the template argument D, the program is ill-formed.
|
//for the template argument D, the program is ill-formed.
|
||||||
BOOST_STATIC_ASSERT(!bmupmu::is_pointer<D>::value);
|
BOOST_STATIC_ASSERT(!bmupmu::is_pointer<D>::value);
|
||||||
@@ -444,7 +448,12 @@ class unique_ptr
|
|||||||
BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_ptr<T BOOST_MOVE_I Pointer BOOST_MOVE_I pointer>::type* =0)
|
BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_ptr<T BOOST_MOVE_I Pointer BOOST_MOVE_I pointer>::type* =0)
|
||||||
) BOOST_NOEXCEPT
|
) BOOST_NOEXCEPT
|
||||||
: m_data(p, d1)
|
: m_data(p, d1)
|
||||||
{}
|
{
|
||||||
|
//If T is not an array type, element_type_t<Pointer> derives from T
|
||||||
|
//it uses the default deleter and T has no virtual destructor, then you have a problem
|
||||||
|
BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor
|
||||||
|
<D, typename bmupd::get_element_type<Pointer>::type>::value ));
|
||||||
|
}
|
||||||
|
|
||||||
//! <b>Effects</b>: Same effects as <tt>template<class Pointer> unique_ptr(Pointer p, deleter_arg_type1 d1)</tt>
|
//! <b>Effects</b>: Same effects as <tt>template<class Pointer> unique_ptr(Pointer p, deleter_arg_type1 d1)</tt>
|
||||||
//! and additionally <tt>get() == nullptr</tt>
|
//! and additionally <tt>get() == nullptr</tt>
|
||||||
@@ -477,7 +486,12 @@ class unique_ptr
|
|||||||
BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_ptr<T BOOST_MOVE_I Pointer BOOST_MOVE_I pointer>::type* =0)
|
BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_ptr<T BOOST_MOVE_I Pointer BOOST_MOVE_I pointer>::type* =0)
|
||||||
) BOOST_NOEXCEPT
|
) BOOST_NOEXCEPT
|
||||||
: m_data(p, ::boost::move(d2))
|
: m_data(p, ::boost::move(d2))
|
||||||
{}
|
{
|
||||||
|
//If T is not an array type, element_type_t<Pointer> derives from T
|
||||||
|
//it uses the default deleter and T has no virtual destructor, then you have a problem
|
||||||
|
BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor
|
||||||
|
<D, typename bmupd::get_element_type<Pointer>::type>::value ));
|
||||||
|
}
|
||||||
|
|
||||||
//! <b>Effects</b>: Same effects as <tt>template<class Pointer> unique_ptr(Pointer p, deleter_arg_type2 d2)</tt>
|
//! <b>Effects</b>: Same effects as <tt>template<class Pointer> unique_ptr(Pointer p, deleter_arg_type2 d2)</tt>
|
||||||
//! and additionally <tt>get() == nullptr</tt>
|
//! and additionally <tt>get() == nullptr</tt>
|
||||||
@@ -519,7 +533,12 @@ class unique_ptr
|
|||||||
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)
|
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)
|
||||||
) BOOST_NOEXCEPT
|
) BOOST_NOEXCEPT
|
||||||
: m_data(u.release(), ::boost::move_if_not_lvalue_reference<E>(u.get_deleter()))
|
: m_data(u.release(), ::boost::move_if_not_lvalue_reference<E>(u.get_deleter()))
|
||||||
{}
|
{
|
||||||
|
//If T is not an array type, U derives from T
|
||||||
|
//it uses the default deleter and T has no virtual destructor, then you have a problem
|
||||||
|
BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor
|
||||||
|
<D, typename unique_ptr<U, E>::pointer>::value ));
|
||||||
|
}
|
||||||
|
|
||||||
//! <b>Requires</b>: The expression <tt>get_deleter()(get())</tt> shall be well formed, shall have well-defined behavior,
|
//! <b>Requires</b>: The expression <tt>get_deleter()(get())</tt> shall be well formed, shall have well-defined behavior,
|
||||||
//! and shall not throw exceptions.
|
//! and shall not throw exceptions.
|
||||||
@@ -673,6 +692,10 @@ class unique_ptr
|
|||||||
BOOST_MOVE_DOC1ST(void, typename bmupd::enable_up_ptr<T BOOST_MOVE_I Pointer BOOST_MOVE_I pointer BOOST_MOVE_I void>::type)
|
BOOST_MOVE_DOC1ST(void, typename bmupd::enable_up_ptr<T BOOST_MOVE_I Pointer BOOST_MOVE_I pointer BOOST_MOVE_I void>::type)
|
||||||
reset(Pointer p) BOOST_NOEXCEPT
|
reset(Pointer p) BOOST_NOEXCEPT
|
||||||
{
|
{
|
||||||
|
//If T is not an array type, element_type_t<Pointer> derives from T
|
||||||
|
//it uses the default deleter and T has no virtual destructor, then you have a problem
|
||||||
|
BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor
|
||||||
|
<D, typename bmupd::get_element_type<Pointer>::type>::value ));
|
||||||
pointer tmp = m_data.m_p;
|
pointer tmp = m_data.m_p;
|
||||||
m_data.m_p = p;
|
m_data.m_p = p;
|
||||||
if(tmp) m_data.deleter()(tmp);
|
if(tmp) m_data.deleter()(tmp);
|
||||||
|
@@ -231,6 +231,7 @@ Global
|
|||||||
..\..\..\..\boost\move\detail\move_helpers.hpp = ..\..\..\..\boost\move\detail\move_helpers.hpp
|
..\..\..\..\boost\move\detail\move_helpers.hpp = ..\..\..\..\boost\move\detail\move_helpers.hpp
|
||||||
..\..\..\..\boost\move\traits.hpp = ..\..\..\..\boost\move\traits.hpp
|
..\..\..\..\boost\move\traits.hpp = ..\..\..\..\boost\move\traits.hpp
|
||||||
..\..\..\..\boost\move\unique_ptr.hpp = ..\..\..\..\boost\move\unique_ptr.hpp
|
..\..\..\..\boost\move\unique_ptr.hpp = ..\..\..\..\boost\move\unique_ptr.hpp
|
||||||
|
..\..\..\..\boost\move\detail\unique_ptr_meta_utils.hpp = ..\..\..\..\boost\move\detail\unique_ptr_meta_utils.hpp
|
||||||
..\..\test\unique_ptr_test_utils_beg.hpp = ..\..\test\unique_ptr_test_utils_beg.hpp
|
..\..\test\unique_ptr_test_utils_beg.hpp = ..\..\test\unique_ptr_test_utils_beg.hpp
|
||||||
..\..\test\unique_ptr_test_utils_end.hpp = ..\..\test\unique_ptr_test_utils_end.hpp
|
..\..\test\unique_ptr_test_utils_end.hpp = ..\..\test\unique_ptr_test_utils_end.hpp
|
||||||
..\..\..\..\boost\move\utility.hpp = ..\..\..\..\boost\move\utility.hpp
|
..\..\..\..\boost\move\utility.hpp = ..\..\..\..\boost\move\utility.hpp
|
||||||
|
Reference in New Issue
Block a user