2
\$\begingroup\$

dynamic_pointer_cast is only implemented for std::shared_ptr, I need it for unique pointers.

The wrinkle is that dynamic_casting a pointer could fail (yield nullptr), what to do in that case? I decided that in that case i would like the original pointer to remain intact. So i have implemented the following:

template< typename T, typename S >
inline std::unique_ptr<T> dynamic_pointer_cast(std::unique_ptr<S>&& ptr_)
{
    T* const converted_ptr = dynamic_cast<T*>(ptr_.get());
    if (!converted_ptr)
        // cast failed, leave input untouched, return nullptr
        return nullptr;

    // cast succeeded, clear input, return casted ptr
    ptr_.release();
    return std::unique_ptr<T>(converted_ptr);
}

Testing code:

#include <memory>
int main(int argc, char **argv)
{
    std::unique_ptr<Base> basePtr = std::make_unique<Derived1>();
    // this should fail, basePtr should remain non-empty, return should be empty
    auto deriv2Ptr = dynamic_pointer_cast<Derived2>(std::move(basePtr));
    // this should succeed, basePtr should become empty, return should be non-empty
    auto deriv1Ptr = dynamic_pointer_cast<Derived1>(std::move(basePtr));
    
    return 0;
}

Is this safe? Does the interface make sense? For the latter question: I decided to take an R-value ref so users have to write std::move, denoting pointer will be emptied. But then it may not if the cast fails... Normal ref is the other option, but then its less clear at the call site that the unique_ptr will likely be cleared.

\$\endgroup\$
0
1
\$\begingroup\$
  • Since it's a template function, it doesn't need to be marked inline.

  • It would be nice to handle custom deleters too. We can access the deleter with ptr_.get_deleter().

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.