There is the family of boost pointer cast (boost::static_pointer_cast, boost::dynamic_pointer_cast, ...) that allow a developer to write generic code by casting pointers regardless of whether they are some smart pointer (e.g. shared_ptr) or plain pointers.
However, those functions have not been implemented for unique_ptr, because they create a copy of their pointer and unique_pointers can not be copied.
In my case I still needed to cast some unique_ptr and since it's ok to move unique_ptrs I wrote a function that does exactly that.
The code is below – Comments are very, very welcome. It works for my case, but I am sure it is not as generic and safe as it should be ;) . Specifically, for a library, it should be made to work on any kind of smart/plain pointer. Not just unique_ptr.
Is there any interest to include a boost::static_moving_pointer_cast and the other types of casts in boost?
Best,
Karolin
/// Dynamic cast a unique_ptr.
///
/// This function shall move the pointer in in_ptr, into
/// a new unique_pointer of the desire type, dynamic_casting
/// it in the process.
/// In given pointer shall contain a NULL pointer afterwards.
///
/// If unsuccessful, function shall throw an error and leave
/// in_ptr unmodified.
///
/// This behaviour contrasts a bit with the behaviour of the
/// normal dynamic_cast:
/// 1. dynamic_cast copies objects, this moves them since
/// unique_pointers can not be copied.
/// 2. dynamic_cast returns a NULL pointer if the pointer to
/// cast is of an incomplete type, this throws
/// incomplete_cast instead, to ease error handling.
///
/// @tparam T The type to convert to (as non-pointer)
/// @tparam F The type to convert from (as non-pointer)
/// @param in_ptr The unique_ptr to cast
/// @return in_ptr, cast to the desired type
template<typename T, typename F>
std::unique_ptr<T> dynamic_moving_pointer_cast(std::unique_ptr<F> &in_ptr) {
// Exception safety: If The dynamic cast throws an error,
// or of we throw incomplete_cast, in_ptr will still be
// unmodified
T *plain_out_ptr = dynamic_cast<F*>(in_ptr.get());
if (plain_out_ptr == NULL && in_ptr.get() != NULL)
throw incomplete_cast();
// Exception safety: Both operations are noexcept
in_ptr.release();
return std::unique_ptr<T>(plain_out_ptr);
}
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
The argument should be &&, not &, or else you won't be able to bind to r-values.
> // Exception safety: If The dynamic cast throws an error,
> // or of we throw incomplete_cast, in_ptr will still be
> // unmodified
> T *plain_out_ptr = dynamic_cast<F*>(in_ptr.get());
> if (plain_out_ptr == NULL && in_ptr.get() != NULL)
> throw incomplete_cast();
>
> // Exception safety: Both operations are noexcept
> in_ptr.release();
> return std::unique_ptr<T>(plain_out_ptr);
> }
It would nice to generalize this to arbitrary smart pointers, because
even for copyable
smart pointers (e.g. shared_ptr, intrusive_ptr), there is interest in
"cast moving" to
avoid needlessly touching the reference count in such case (better performance).
However, I am not sure we can implement this non-intrusively.
--
François
Just wondering if we can not make dynamic_pointer_cast to work as your
dynamic_moving_pointer_cast, when the parameter is a rvalue reference
template<class T, class U>
shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> && r) noexcept;
C++ International Standard
The use will be
dynamic_pointer_cast<U>(ret_up());
dynamic_pointer_cast<U>(move(up));
Vicente
Vicente