boost.png (6897 bytes)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, 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 a static pointer cast this way:

template<class T, class U>
    shared_ptr<T> static_pointer_cast(shared_ptr<U> const &r);

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.

Synopsis

namespace boost {

template<class T, class U>
inline T* static_pointer_cast(U *ptr)
  { return static_cast<T*>(ptr); }

template<class T, class U>
inline T* dynamic_pointer_cast(U *ptr)
  { return dynamic_cast<T*>(ptr); }

template<class T, class U>
inline T* const_pointer_cast(U *ptr)
  { return const_cast<T*>(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<U> static_pointer_cast(std::shared_ptr<T> ptr);

template<class T, class U>
inline std::shared_ptr<U> dynamic_pointer_cast(std::shared_ptr<T> ptr);

template<class T, class U>
inline std::shared_ptr<U> const_pointer_cast(std::shared_ptr<T> ptr);

template<class T, class U>
inline std::shared_ptr<U> reinterpret_pointer_cast(std::shared_ptr<T> ptr);

template<class T, class U>
inline std::unique_ptr<U> static_pointer_cast(std::unique_ptr<T> &&ptr);

template<class T, class U>
inline std::unique_ptr<U> dynamic_pointer_cast(std::unique_ptr<T> &&ptr);

template<class T, class U>
inline std::unique_ptr<U> const_pointer_cast(std::unique_ptr<T> &&ptr);

template<class T, class U>
inline std::unique_ptr<U> reinterpret_pointer_cast(std::unique_ptr<T> &&ptr);
  
} // 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.

Memory Safety

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>

int destructed = 0;

struct base {
  ~base() {
    // ...
  }
};

struct child : base {
  virtual ~child() {
    destructed++;
  }
}

int main() {
  {
    std::unique_ptr 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>

class base
{
public:

   virtual ~base()
   {
   }
};

class derived: public base
{
};

template <class BasePtr>
void check_if_it_is_derived(const BasePtr &ptr)
{
   assert(boost::dynamic_pointer_cast<derived>(ptr) != 0);
}

int main()
{
   // 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_if_it_is_derived(ptr);
   check_if_it_is_derived(sptr);
   
   // Ok!
   
   delete ptr;
   return 0;
}

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


$Date$

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>.)