From 3aa720714d76b57fd758e2507bd0c0d1105e60b4 Mon Sep 17 00:00:00 2001
From: Peter Dimov The pointer cast functions ( There is test/example code in pointer_cast_test.cpp.
+ width="277" align="middle" border="0" />pointer_cast
pointer_cast
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, std::shared_ptr and std::unique_ptr. The functions
- are defined in boost/pointer_cast.hpp.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.
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, 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.
-++ for raw pointers,+std::shared_ptr
andstd::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> @@ -48,84 +48,91 @@ inline T* reinterpret_pointer_cast(U *ptr) { return reinterpret_cast<T*>(ptr); } template<class T, class U> -inline std::shared_ptr<U> static_pointer_cast(std::shared_ptr<T> ptr); +inline std::shared_ptr<T> static_pointer_cast(std::shared_ptr<U> const& r); template<class T, class U> -inline std::shared_ptr<U> dynamic_pointer_cast(std::shared_ptr<T> ptr); +inline std::shared_ptr<T> dynamic_pointer_cast(std::shared_ptr<U> const& r); template<class T, class U> -inline std::shared_ptr<U> const_pointer_cast(std::shared_ptr<T> ptr); +inline std::shared_ptr<T> const_pointer_cast(std::shared_ptr<U> const& r); template<class T, class U> -inline std::shared_ptr<U> reinterpret_pointer_cast(std::shared_ptr<T> ptr); +inline std::shared_ptr<T> reinterpret_pointer_cast(std::shared_ptr<U> const& r); template<class T, class U> -inline std::unique_ptr<U> static_pointer_cast(std::unique_ptr<T> &&ptr); +inline std::unique_ptr<T> static_pointer_cast(std::unique_ptr<U>&& r); template<class T, class U> -inline std::unique_ptr<U> dynamic_pointer_cast(std::unique_ptr<T> &&ptr); +inline std::unique_ptr<T> dynamic_pointer_cast(std::unique_ptr<U>&& r); template<class T, class U> -inline std::unique_ptr<U> const_pointer_cast(std::unique_ptr<T> &&ptr); +inline std::unique_ptr<T> const_pointer_cast(std::unique_ptr<U>&& r); template<class T, class U> -inline std::unique_ptr<U> reinterpret_pointer_cast(std::unique_ptr<T> &&ptr); +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 for raw pointers are just - wrappers around standard C++ cast operators.
+
As you can see from the above synopsis, the pointer cast functions for raw pointers are just + wrappers around standard C++ cast operators.
-It is possible to write unsafe code, when upcasting to a base type without virtual destructor. - Consider the following example:
--#include <memory> -#include <utility> -#include <boost/pointer_cast.hpp> -#include <boost/make_unique.hpp> +-The pointer casts for
-int destructed = 0; +std::shared_ptr
are aliases of the corresponding standard + functions with the same names and equivalent to the + functions takingboost::shared_ptr
.The pointer casts for
-struct base { - ~base() { - // ... - } -}; +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++-struct child : base { - virtual ~child() { - destructed++; - } -} - -int main() { - { - std::unique_ptrRequires: 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.
+tmp = boost::make_unique (); - std::unique_ptr sink = boost::static_pointer_cast ( std::move(tmp) ); - } - - // child::~child was never called - assert(destructed == 0); - - return 0; -} -
In this example, the child destructor child::~child was never called, because the child* in tmp - was downcast to a base* and moved into sink. The destructor of tmp did essentially nothing, because - it contained nullptr during destruction; sink deleted the pointer, but since base::~base is non-virtual - the child destructor was never called.
-boost::static_pointer_cast and boost::dynamic_pointer_cast for std::unique_ptr prevent the above scenario - by raising a compiler error when such a cast is detected.
-The overloads for std::shared_ptr and boost::shared_ptr are not prone to this problem, since they internally - always store the original pointer with the original type.
-The plain pointer casts are in principle also prone to that problem, but it is assumed that raw pointers - are non-owning, so no checking is performed.
- --+++Example
++-#include <boost/pointer_cast.hpp> #include <boost/shared_ptr.hpp> @@ -150,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>.)