static_pointer_cast<T>(..) for weak_ptr<T>s
In the last post I mentioned that the following functions are not defined for weak_ptr<T> (in Boost 1_37_0):
- const_pointer_cast<T>(..)
- static_pointer_cast<T>(..)
- dynamic_pointer_cast<T>(..)
Boost is a very nice and carefully thought-out library, so these functions may be missing for a good reason. Or maybe they’re just considered not very important because weak pointers are not often passed around and copied on the stack. In any case, here is one way to define static_pointer_cast<T>(..) — the same pattern can be used for the other two functions.
# include <boost/assert.hpp>
# include <boost/shared_ptr.hpp>
# include <boost/weak_ptr.hpp>
# include <boost/pointer_cast.hpp>
namespace boost {
template
< typename TRG_T
, typename SRC_T
>
weak_ptr< TRG_T >
static_pointer_cast( weak_ptr< SRC_T > const & wp_src)
//
// This works even if the source weak_ptr is null or
// expired.
//
// No throw - this should never throw an exception.
{
// Get a shared_ptr from the weak_ptr.
// Use weak_ptr.lock( ) so this will not throw
// bad_weak_ptr if the weak_ptr is expired.
shared_ptr< SRC_T >
sp_src(
wp_src.lock( ));
BOOST_ASSERT( wp_src.expired( ) == ! sp_src);
// Cast the shared_ptr to the target type.
shared_ptr< TRG_T >
sp_trg(
static_pointer_cast< TRG_T >( sp_src));
// Auto-cast the shared_ptr< TRG_T > to the
// weak_ptr< TRG_T > return type.
return sp_trg;
}
} /* end namespace boost */
It would probably be more efficient to build this into the weak_ptr<T> class like it is built into the shared_ptr<T> class, but this will do.
Here is how you’d use static_pointer_cast<T>(..).
using boost::shared_ptr;
using boost::weak_ptr;
using boost::static_pointer_cast;
class
base_type
{ public: virtual ~base_type( ) { } };
class
derived_type
: public base_type
{ };
// Make a shared pointer that owns a new object.
shared_ptr< derived_type >
sp_derived(
new derived_type);
// Make a weak pointer to that same object.
weak_ptr< derived_type >
wp_derived(
sp_derived);
// Weak pointers upcast normally, even when they
// are null or expired.
weak_ptr< base_type >
wp_base(
wp_derived);
// Our new static_pointer_cast works with
// weak pointers.
weak_ptr< derived_type >
wp_derived2(
static_pointer_cast< derived_type >( wp_base)
);
I noticed when writing this that weak_ptr<T> does not have an automatic boolean conversion like other pointer types. You cannot write code like if ( weak_ptr_inst ).. or assert( ! weak_ptr_inst). Instead you have to use weak_ptr_inst.expired( ). This is because it would be easy to forget that a weak pointer can expire at any time, which can lead to bugs that fail only occasionally and are hard to reproduce.
// Assume weak_ptr bool operator is defined
// (which it isn't).
template< typename T >
class
weak_ptr
{
... other stuff ...
// Very simple bool operator.
operator bool( ) const { return ! expired( ); }
};
...
weak_ptr< my_class >
weak_ptr_inst(
shared_ptr_inst);
if ( weak_ptr_inst ) {
... Here you might find dangerous code that assumes
... weak_ptr_inst is set (not null, not expired).
... Code should always assume a weak_ptr can
... expire unless the same code is holding a
... shared_ptr to the same target object.
}
if ( ! weak_ptr_inst.expired( ) ) {
... This is the same as above, but it might be safer
... because the explicit call to expired( ) reminds
... us we are working with a weak_ptr, which
... doesn't fit into more common pointer patterns.
}
Comments
Leave a Reply