Boost logo

Boost :

Subject: Re: [boost] [smart_ptr] Moving cast for unique_ptr
From: Francois Duranleau (xiao.bai.xiong_at_[hidden])
Date: 2015-10-06 07:45:58


On Tue, Oct 6, 2015 at 6:19 AM, Karolin Varner <karo_at_[hidden]> wrote:
> Hi all!
>
> 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) {

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

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk