diff --git a/include/boost/pointer_cast.hpp b/include/boost/pointer_cast.hpp index 6e532eb..5af4971 100644 --- a/include/boost/pointer_cast.hpp +++ b/include/boost/pointer_cast.hpp @@ -10,6 +10,8 @@ #ifndef BOOST_POINTER_CAST_HPP #define BOOST_POINTER_CAST_HPP +#include + namespace boost { //static_pointer_cast overload for raw pointers @@ -42,4 +44,78 @@ inline T* reinterpret_pointer_cast(U *ptr) } // namespace boost +#if !defined( BOOST_NO_CXX11_SMART_PTR ) + +#include +#include +#include + +namespace boost { + +//static_pointer_cast overload for std::shared_ptr +using std::static_pointer_cast; + +//dynamic_pointer_cast overload for std::shared_ptr +using std::dynamic_pointer_cast; + +//const_pointer_cast overload for std::shared_ptr +using std::const_pointer_cast; + +//reinterpret_pointer_cast overload for std::shared_ptr +template std::shared_ptr reinterpret_pointer_cast(const std::shared_ptr & r ) BOOST_NOEXCEPT +{ + (void) reinterpret_cast< T* >( static_cast< U* >( 0 ) ); + + typedef typename std::shared_ptr::element_type E; + + E * p = reinterpret_cast< E* >( r.get() ); + return std::shared_ptr( r, p ); +} + +//static_pointer_cast overload for std::unique_ptr +template std::unique_ptr static_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT +{ + (void) static_cast< T* >( static_cast< U* >( 0 ) ); + + typedef typename std::unique_ptr::element_type E; + + return std::unique_ptr( static_cast( r.release() ) ); +} + +//dynamic_pointer_cast overload for std::unique_ptr +template std::unique_ptr dynamic_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT +{ + (void) dynamic_cast< T* >( static_cast< U* >( 0 ) ); + + BOOST_STATIC_ASSERT_MSG( boost::has_virtual_destructor::value, "The target of dynamic_pointer_cast must have a virtual destructor." ); + + T * p = dynamic_cast( r.get() ); + if( p ) r.release(); + return std::unique_ptr( p ); +} + +//const_pointer_cast overload for std::unique_ptr +template std::unique_ptr const_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT +{ + (void) const_cast< T* >( static_cast< U* >( 0 ) ); + + typedef typename std::unique_ptr::element_type E; + + return std::unique_ptr( const_cast( r.release() ) ); +} + +//reinterpret_pointer_cast overload for std::unique_ptr +template std::unique_ptr reinterpret_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT +{ + (void) reinterpret_cast< T* >( static_cast< U* >( 0 ) ); + + typedef typename std::unique_ptr::element_type E; + + return std::unique_ptr( reinterpret_cast( r.release() ) ); +} + +} // namespace boost + +#endif // #if !defined( BOOST_NO_CXX11_SMART_PTR ) + #endif //BOOST_POINTER_CAST_HPP diff --git a/pointer_cast.html b/pointer_cast.html index 2ab0859..bf63043 100644 --- a/pointer_cast.html +++ b/pointer_cast.html @@ -2,16 +2,16 @@ pointer_cast - +

boost.png (6897 bytes)pointer_cast

+ width="277" align="middle" border="0" />pointer_cast

The pointer cast functions (boost::static_pointer_cast boost::dynamic_pointer_cast boost::reinterpret_pointer_cast boost::const_pointer_cast) - provide a way to write generic pointer castings for raw pointers. The functions - are defined in boost/pointer_cast.hpp.

-

There is test/example code in pointer_cast_test.cpp.

+ provide a way to write generic pointer castings for raw pointers, std::shared_ptr and std::unique_ptr. The functions + are defined in boost/pointer_cast.hpp.

+

There is test/example code in pointer_cast_test.cpp.

Rationale

Boost smart pointers usually overload those functions to provide a mechanism to emulate pointers casts. For example, boost::shared_ptr<...> implements @@ -20,15 +20,15 @@ template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U> const &r); -

Pointer cast functions from boost/pointer_cast.hpp +

Pointer cast functions from boost/pointer_cast.hpp are overloads of boost::static_pointer_cast, boost::dynamic_pointer_cast, boost::reinterpret_pointer_cast and boost::const_pointer_cast - for raw pointers. This way when developing pointer type independent classes, - for example, memory managers or shared memory compatible classes, the same code - can be used for raw and smart pointers.

-

Synopsis

-
-
+            for raw pointers, std::shared_ptr and std::unique_ptr. This way when developing
+            pointer type independent classes, for example, memory managers or shared memory compatible classes, the same
+            code can be used for raw and smart pointers.

+

Synopsis

+
+
 namespace boost {
 
 template<class T, class U>
@@ -46,15 +46,93 @@ inline T* const_pointer_cast(U *ptr)
 template<class T, class U>
 inline T* reinterpret_pointer_cast(U *ptr)
   { return reinterpret_cast<T*>(ptr); }
+
+template<class T, class U>
+inline std::shared_ptr<T> static_pointer_cast(std::shared_ptr<U> const& r);
+
+template<class T, class U>
+inline std::shared_ptr<T> dynamic_pointer_cast(std::shared_ptr<U> const& r);
+
+template<class T, class U>
+inline std::shared_ptr<T> const_pointer_cast(std::shared_ptr<U> const& r);
+
+template<class T, class U>
+inline std::shared_ptr<T> reinterpret_pointer_cast(std::shared_ptr<U> const& r);
+
+template<class T, class U>
+inline std::unique_ptr<T> static_pointer_cast(std::unique_ptr<U>&& r);
+
+template<class T, class U>
+inline std::unique_ptr<T> dynamic_pointer_cast(std::unique_ptr<U>&& r);
+
+template<class T, class U>
+inline std::unique_ptr<T> const_pointer_cast(std::unique_ptr<U>&& r);
+
+template<class T, class U>
+inline std::unique_ptr<T> reinterpret_pointer_cast(std::unique_ptr<U>&& r);
   
 } // namespace boost
-
-
-

As you can see from the above synopsis, the pointer cast functions are just - wrappers around standard C++ cast operators.

-

Example

-
-
+
+
+

As you can see from the above synopsis, the pointer cast functions for raw pointers are just + wrappers around standard C++ cast operators.

+ +

The pointer casts for std::shared_ptr are aliases of the corresponding standard + functions with the same names and equivalent to the + functions taking boost::shared_ptr.

+ +

The pointer casts for std::unique_ptr are documented below.

+ +

static_pointer_cast

+
template<class T, class U>
+  unique_ptr<T> static_pointer_cast(unique_ptr<U>&& r); // never throws
+
+

Requires: The expression static_cast<T*>( (U*)0 ) + must be well-formed.

+

Returns: unique_ptr<T>( static_cast<typename unique_ptr<T>::element_type*>(r.release()) ).

+

Throws: nothing.

+

Notes: the seemingly equivalent expression + unique_ptr<T>(static_cast<T*>(r.get())) + will eventually result in undefined behavior, attempting to delete the same + object twice.

+
+

const_pointer_cast

+
template<class T, class U>
+  unique_ptr<T> const_pointer_cast(unique_ptr<U>&& r); // never throws
+
+

Requires: The expression const_cast<T*>( (U*)0 ) + must be well-formed.

+

Returns: unique_ptr<T>( const_cast<typename unique_ptr<T>::element_type*>(r.release()) ).

+

Throws: nothing.

+
+

dynamic_pointer_cast

+
template<class T, class U>
+  unique_ptr<T> dynamic_pointer_cast(unique_ptr<U>&& r);
+
+

Requires: The expression dynamic_cast<T*>( (U*)0 ) + must be well-formed. T must have a virtual destructor.

+

Returns:

+
    +
  • + When dynamic_cast<typename unique_ptr<T>::element_type*>(r.get()) returns a nonzero value, + unique_ptr<T>(dynamic_cast<typename unique_ptr<T>::element_type*>(r.release()));
  • +
  • + Otherwise, unique_ptr<T>().
+

Throws: nothing.

+
+

reinterpret_pointer_cast

+
template<class T, class U>
+  unique_ptr<T> reinterpret_pointer_cast(unique_ptr<U>&& r); // never throws
+
+

Requires: The expression reinterpret_cast<T*>( (U*)0 ) + must be well-formed.

+

Returns: unique_ptr<T>( reinterpret_cast<typename unique_ptr<T>::element_type*>(r.release()) ).

+

Throws: nothing.

+
+ +

Example

+
+
 #include <boost/pointer_cast.hpp>
 #include <boost/shared_ptr.hpp>
 
@@ -79,28 +157,27 @@ void check_if_it_is_derived(const BasePtr &ptr)
 
 int main()
 {
-   // Create a raw and a shared_ptr
+   // Create a raw and a shared_ptr
 
    base *ptr = new derived;
    boost::shared_ptr<base> sptr(new derived);
    
-   // Check that base pointer points actually to derived class
+   // Check that base pointer points actually to derived class
 
    check_if_it_is_derived(ptr);
    check_if_it_is_derived(sptr);
    
-   // Ok!
+   // Ok!
    
    delete ptr;
    return 0;
-}
-
-

The example demonstrates how the generic pointer casts help us create pointer - independent code.

-
-

$Date$

+}
+
+

The example demonstrates how the generic pointer casts help us create pointer + independent code.

+

Copyright 2005 Ion Gaztaņaga. Use, modification, and distribution are subject to - the Boost Software License, Version 1.0. (See accompanying file - LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)

+ the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)

diff --git a/shared_ptr.htm b/shared_ptr.htm index 5c756f8..1cd0bc4 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -222,7 +222,7 @@ void bad() shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r); // never throws template<class T, class U> - shared_ptr<T> reinterpet_pointer_cast(shared_ptr<U> const & r); // never throws + shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U> const & r); // never throws template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr<Y> const & p); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 11c41c2..7c31ce5 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -29,6 +29,7 @@ import testing ; [ compile-fail shared_ptr_compare_fail.cpp ] [ run shared_ptr_alloc2_test.cpp ] [ run pointer_cast_test.cpp ] + [ run cpp11_pointer_cast_test.cpp ] [ compile pointer_to_other_test.cpp ] [ run auto_ptr_rv_test.cpp ] [ run shared_ptr_alias_test.cpp ] @@ -186,5 +187,19 @@ import testing ; [ run sp_hash_test2.cpp ] [ run sp_hash_test3.cpp ] + + [ run pointer_cast_test2.cpp ] + + [ compile-fail pointer_cast_st_fail.cpp ] + [ compile-fail pointer_cast_st_fail2.cpp ] + [ compile-fail pointer_cast_st_fail3.cpp ] + + [ compile-fail pointer_cast_co_fail.cpp ] + [ compile-fail pointer_cast_co_fail2.cpp ] + [ compile-fail pointer_cast_co_fail3.cpp ] + + [ compile-fail pointer_cast_dy_fail.cpp ] + [ compile-fail pointer_cast_dy_fail2.cpp ] + [ compile-fail pointer_cast_dy_fail3.cpp ] ; } diff --git a/test/cpp11_pointer_cast_test.cpp b/test/cpp11_pointer_cast_test.cpp new file mode 100644 index 0000000..a9361c3 --- /dev/null +++ b/test/cpp11_pointer_cast_test.cpp @@ -0,0 +1,224 @@ +// +// cpp11_pointer_cast_test.cpp - a test for boost/pointer_cast.hpp with std::shared_ptr and std::unique_ptr +// +// Copyright (c) 2016 Karolin Varner +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) \ + || defined( BOOST_NO_CXX11_HDR_FUNCTIONAL ) \ + || defined( BOOST_NO_CXX11_HDR_UTILITY ) \ + || defined( BOOST_NO_CXX11_LAMBDAS ) \ + || defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +// We expect all the features or none of the features to be +// available, since we should be on C++11 +int main() { return 0; } + +#else + +namespace +{ + +// Let's create these inheritance relationship: +// +// base base2 +// | | +// derived +// | +// derived_derived +// + +class base +{ + public: + virtual ~base(){} + int filler [5]; +}; + +class base2 +{ +public: + + virtual ~base2(){} + int filler [5]; +}; + +class derived + : public base, public base2 +{ + int filler [5]; +}; + +class derived_derived + : public derived +{ + int filler [5]; +}; + +// And now some simple check functions + +#if !defined( BOOST_NO_RTTI ) + +template +bool check_dynamic_pointer_cast(const BasePtr &ptr) +{ + //Check that dynamic_pointer_cast versus dynamic_cast + return + //Correct cast with dynamic_pointer_cast + boost::get_pointer(boost::dynamic_pointer_cast(ptr)) == + //Correct cast with dynamic_cast + dynamic_cast(boost::get_pointer(ptr)) + && + //Incorrect cast with dynamic_pointer_cast + boost::get_pointer(boost::dynamic_pointer_cast(ptr)) == + //Incorrect cast with dynamic_cast + dynamic_cast(boost::get_pointer(ptr)); +} + +#endif + +template +bool check_static_pointer_cast(const BasePtr &ptr) +{ + return + //Cast base -> derived -> base2 using static_pointer_cast + boost::get_pointer( + boost::static_pointer_cast( + boost::static_pointer_cast(ptr))) == + //Now the same with static_cast + static_cast(static_cast(boost::get_pointer(ptr))); +} + +template +bool check_const_pointer_cast(const BasePtr &ptr) +{ + return + //Unconst and const again using const_pointer_cast + boost::get_pointer( + boost::const_pointer_cast + (boost::const_pointer_cast(ptr))) == + //Now the same with const_cast + const_cast(const_cast(boost::get_pointer(ptr))); +} + +template +void check_all_copy_casts(const BasePtr &ptr) +{ +#if !defined( BOOST_NO_RTTI ) + BOOST_TEST( check_dynamic_pointer_cast( ptr ) ); +#endif + BOOST_TEST( check_static_pointer_cast( ptr ) ); + BOOST_TEST( check_const_pointer_cast( ptr ) ); +} + + +#if !defined( BOOST_NO_RTTI ) + +template +bool check_dynamic_moving_pointer_cast(std::function f) +{ + BasePtr smart1 = f(), smart2 = f(); + derived* expect1 = dynamic_cast(boost::get_pointer(smart1)); + derived_derived* expect2 = dynamic_cast(boost::get_pointer(smart2)); + //Check that dynamic_pointer_cast versus dynamic_cast + return + //Correct cast with dynamic_pointer_cast + boost::get_pointer(boost::dynamic_pointer_cast( std::move(smart1) )) == expect1 + && + //Incorrect cast with dynamic_pointer_cast + boost::get_pointer(boost::dynamic_pointer_cast( std::move(smart2) )) == expect2; +} + +#endif + +template +bool check_static_moving_pointer_cast(std::function f) +{ + BasePtr smart = f(); + base2 *expect = static_cast(static_cast(boost::get_pointer(smart))); + + return + //Cast base -> derived -> base2 using static_pointer_cast + boost::get_pointer( + boost::static_pointer_cast( + boost::static_pointer_cast( std::move(smart) ))) == + //Now the same with static_cast + expect; +} + +template +bool check_const_moving_pointer_cast(std::function f) +{ + BasePtr smart = f(); + const base *expect = const_cast(const_cast(boost::get_pointer(smart))); + return + //Unconst and const again using const_pointer_cast + boost::get_pointer( + boost::const_pointer_cast + (boost::const_pointer_cast( std::move(smart) ))) == + //Now the same with const_cast + expect; +} + +template +void check_all_moving_casts(std::function f) { +#if !defined( BOOST_NO_RTTI ) + BOOST_TEST( check_dynamic_moving_pointer_cast( f ) ); +#endif + BOOST_TEST( check_static_moving_pointer_cast( f ) ); + BOOST_TEST( check_const_moving_pointer_cast( f ) ); +} + +} + +int main() +{ + + std::shared_ptr std_shared(new derived); + boost::shared_ptr boost_shared(new derived); + base *plain = boost_shared.get(); + + // plain & boost::shared_ptr moving pointer_cast checks; there + // is no specific handleing for those types at the moment; this + // test just makes sure they won't break when std::move() is used + // in generic code + + check_all_moving_casts>([&boost_shared]() { + return boost_shared; + }); + + check_all_moving_casts([plain]() { + return plain; + }); + + // std::shared_ptr casts + + check_all_copy_casts(std_shared); + check_all_moving_casts>([&std_shared]() { + return std_shared; + }); + + // std::unique_ptr casts + + check_all_moving_casts>([]() { + return std::unique_ptr(new derived); + }); + + return boost::report_errors(); +} +#endif diff --git a/test/pointer_cast_co_fail.cpp b/test/pointer_cast_co_fail.cpp new file mode 100644 index 0000000..d8960b2 --- /dev/null +++ b/test/pointer_cast_co_fail.cpp @@ -0,0 +1,18 @@ +// +// A negative test for unique_ptr const_cast +// +// Copyright 2016 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include + +int main() +{ + std::unique_ptr p1( new int ); + std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) ); +} diff --git a/test/pointer_cast_co_fail2.cpp b/test/pointer_cast_co_fail2.cpp new file mode 100644 index 0000000..7fa8e18 --- /dev/null +++ b/test/pointer_cast_co_fail2.cpp @@ -0,0 +1,18 @@ +// +// A negative test for unique_ptr const_cast +// +// Copyright 2016 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include + +int main() +{ + std::unique_ptr p1( new int[ 1 ] ); + std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) ); +} diff --git a/test/pointer_cast_co_fail3.cpp b/test/pointer_cast_co_fail3.cpp new file mode 100644 index 0000000..d8872c8 --- /dev/null +++ b/test/pointer_cast_co_fail3.cpp @@ -0,0 +1,29 @@ +// +// A negative test for unique_ptr const_cast +// +// Copyright 2016 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include + +struct B +{ + virtual ~B() + { + } +}; + +struct D: B +{ +}; + +int main() +{ + std::unique_ptr p1( new D[ 1 ] ); + std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) ); +} diff --git a/test/pointer_cast_dy_fail.cpp b/test/pointer_cast_dy_fail.cpp new file mode 100644 index 0000000..c6df69d --- /dev/null +++ b/test/pointer_cast_dy_fail.cpp @@ -0,0 +1,25 @@ +// +// A negative test for unique_ptr dynamic_cast +// +// Copyright 2016 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include + +struct B +{ + virtual ~B() + { + } +}; + +int main() +{ + std::unique_ptr p1( new B ); + std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) ); +} diff --git a/test/pointer_cast_dy_fail2.cpp b/test/pointer_cast_dy_fail2.cpp new file mode 100644 index 0000000..223977a --- /dev/null +++ b/test/pointer_cast_dy_fail2.cpp @@ -0,0 +1,25 @@ +// +// A negative test for unique_ptr dynamic_cast +// +// Copyright 2016 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include + +struct B +{ + virtual ~B() + { + } +}; + +int main() +{ + std::unique_ptr p1( new B[ 1 ] ); + std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) ); +} diff --git a/test/pointer_cast_dy_fail3.cpp b/test/pointer_cast_dy_fail3.cpp new file mode 100644 index 0000000..1ac52e7 --- /dev/null +++ b/test/pointer_cast_dy_fail3.cpp @@ -0,0 +1,29 @@ +// +// A negative test for unique_ptr dynamic_cast +// +// Copyright 2016 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include + +struct B +{ + virtual ~B() + { + } +}; + +struct D: B +{ +}; + +int main() +{ + std::unique_ptr p1( new D[ 1 ] ); + std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) ); +} diff --git a/test/pointer_cast_st_fail.cpp b/test/pointer_cast_st_fail.cpp new file mode 100644 index 0000000..0fcf8c1 --- /dev/null +++ b/test/pointer_cast_st_fail.cpp @@ -0,0 +1,18 @@ +// +// A negative test for unique_ptr static_cast +// +// Copyright 2016 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include + +int main() +{ + std::unique_ptr p1( new int ); + std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) ); +} diff --git a/test/pointer_cast_st_fail2.cpp b/test/pointer_cast_st_fail2.cpp new file mode 100644 index 0000000..3b227b9 --- /dev/null +++ b/test/pointer_cast_st_fail2.cpp @@ -0,0 +1,18 @@ +// +// A negative test for unique_ptr static_cast +// +// Copyright 2016 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include + +int main() +{ + std::unique_ptr p1( new int[ 1 ] ); + std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) ); +} diff --git a/test/pointer_cast_st_fail3.cpp b/test/pointer_cast_st_fail3.cpp new file mode 100644 index 0000000..4ca6a89 --- /dev/null +++ b/test/pointer_cast_st_fail3.cpp @@ -0,0 +1,29 @@ +// +// A negative test for unique_ptr static_cast +// +// Copyright 2016 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include +#include + +struct B +{ + virtual ~B() + { + } +}; + +struct D: B +{ +}; + +int main() +{ + std::unique_ptr p1( new D[ 1 ] ); + std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) ); +} diff --git a/test/pointer_cast_test.cpp b/test/pointer_cast_test.cpp index bd25dd1..ae036fb 100644 --- a/test/pointer_cast_test.cpp +++ b/test/pointer_cast_test.cpp @@ -104,33 +104,25 @@ bool check_const_pointer_cast(const BasePtr &ptr) const_cast(const_cast(boost::get_pointer(ptr))); } +template +void check_all_casts(const BasePtr &ptr) +{ +#if !defined( BOOST_NO_RTTI ) + BOOST_TEST( check_dynamic_pointer_cast( ptr ) ); +#endif + BOOST_TEST( check_static_pointer_cast( ptr ) ); + BOOST_TEST( check_const_pointer_cast( ptr ) ); +} + } int main() { - { - // Try casts with shared_ptr + boost::shared_ptr boost_shared(new derived); + base *plain = boost_shared.get(); - boost::shared_ptr ptr(new derived); - -#if !defined( BOOST_NO_RTTI ) - BOOST_TEST( check_dynamic_pointer_cast( ptr ) ); -#endif - BOOST_TEST( check_static_pointer_cast( ptr ) ); - BOOST_TEST( check_const_pointer_cast( ptr ) ); - } - - { - // Try casts with raw pointer - - boost::scoped_ptr ptr(new derived); - -#if !defined( BOOST_NO_RTTI ) - BOOST_TEST( check_dynamic_pointer_cast( ptr.get() ) ); -#endif - BOOST_TEST( check_static_pointer_cast( ptr.get() ) ); - BOOST_TEST( check_const_pointer_cast( ptr.get() ) ); - } + check_all_casts(boost_shared); + check_all_casts(plain); return boost::report_errors(); } diff --git a/test/pointer_cast_test2.cpp b/test/pointer_cast_test2.cpp new file mode 100644 index 0000000..eb28a5d --- /dev/null +++ b/test/pointer_cast_test2.cpp @@ -0,0 +1,247 @@ +// +// pointer_cast_test2.cpp - a test for unique_ptr casts +// +// Copyright 2016 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// + +#include + +#if defined( BOOST_NO_CXX11_SMART_PTR ) + +int main() +{ + return 0; +} + +#else + +#include +#include +#include + +struct B1 +{ +}; + +struct D1: B1 +{ + ~D1() + { + } +}; + +static void test_static_cast() +{ + { + std::unique_ptr p1( new int ); + int * q1 = p1.get(); + + std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + } + + { + std::unique_ptr p1( new int ); + int * q1 = p1.get(); + + std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + } + + { + std::unique_ptr p1( new int[ 1 ] ); + int * q1 = p1.get(); + + std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + } + + { + std::unique_ptr p1( new int[ 1 ] ); + int * q1 = p1.get(); + + std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + } + + { + std::unique_ptr p1( new D1 ); + D1 * q1 = p1.get(); + + std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + + std::unique_ptr p3 = boost::static_pointer_cast( std::move( p2 ) ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST_EQ( p3.get(), q1 ); + } +} + +static void test_const_cast() +{ + { + std::unique_ptr p1( new int ); + int * q1 = p1.get(); + + std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + + std::unique_ptr p3 = boost::const_pointer_cast( std::move( p2 ) ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST_EQ( p3.get(), q1 ); + } + + { + std::unique_ptr p1( new int[ 1 ] ); + int * q1 = p1.get(); + + std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + + std::unique_ptr p3 = boost::const_pointer_cast( std::move( p2 ) ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST_EQ( p3.get(), q1 ); + } +} + +struct B2 +{ + virtual ~B2() + { + } +}; + +struct C2 +{ + virtual ~C2() + { + } +}; + +struct D2: B2, C2 +{ +}; + +static void test_dynamic_cast() +{ + { + std::unique_ptr p1( new D2 ); + D2 * q1 = p1.get(); + + std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + } + + { + std::unique_ptr p1( new D2 ); + B2 * q1 = p1.get(); + + std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + } + + { + std::unique_ptr p1( new B2 ); + B2 * q1 = p1.get(); + + std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST_EQ( p1.get(), q1 ); + } + + { + D2 * q1 = new D2; + std::unique_ptr p1( q1 ); + + std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + } +} + +static void test_reinterpret_cast() +{ + { + std::unique_ptr p1( new int ); + void * q1 = p1.get(); + + std::unique_ptr p2 = boost::reinterpret_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + + p1 = boost::reinterpret_pointer_cast( std::move( p2 ) ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST_EQ( p1.get(), q1 ); + } + + { + std::unique_ptr p1( new int ); + void * q1 = p1.get(); + + std::unique_ptr p2 = boost::reinterpret_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + + p1 = boost::reinterpret_pointer_cast( std::move( p2 ) ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST_EQ( p1.get(), q1 ); + } + + { + std::unique_ptr p1( new int[ 1 ] ); + void * q1 = p1.get(); + + std::unique_ptr p2 = boost::reinterpret_pointer_cast( std::move( p1 ) ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST_EQ( p2.get(), q1 ); + + p1 = boost::reinterpret_pointer_cast( std::move( p2 ) ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST_EQ( p1.get(), q1 ); + } +} + +int main() +{ + test_static_cast(); + test_const_cast(); + test_dynamic_cast(); + test_reinterpret_cast(); + + return boost::report_errors(); +} + +#endif