I have a class hierarchy as follows:
class BaseSession : public boost::enable_shared_from_this<BaseSession> class DerivedSessionA : public BaseSession class DerivedSessionB : public BaseSession
Within the derived class functions, I regularly call functions like this:
Func(boost::dynamic_pointer_cast<DerivedSessionA>(shared_from_this()));
Since I was working with shared_ptr
to manage the sessions, this was working fine. Recently, I discovered that my use of shared_ptr
is not optimal for this case. That is because these sessions are singleton objects that maintain one socket per client. If socket is reconnected, the session copies used to become zombies.
As workaround, I started passing shared_ptr
by reference rather than copies. This solved the zombie problem.
Ideally, I felt I should be using unique_ptr
to store the session and then pass references to other functions. That opened a whole can of worms.
How do I cast a base class unique_ptr
object to derived class unique_ptr
object? What is the unique_ptr
version of the following line?
Func(boost::dynamic_pointer_cast<DerivedSessionA>(shared_from_this()));
I just want one copy of the session object, everything else should be reference.
The unique_ptr shall not be empty (i.e., its stored pointer shall not be a null pointer) in order to be dereferenciable. This can easily be checked by casting the unique_ptr object to bool (see unique_ptr::operator bool). It is equivalent to: *get().
Use unique_ptr when you want a single pointer to an object that will be reclaimed when that single pointer is destroyed. Use shared_ptr when you want multiple pointers to the same resource.
Use unique_ptr when you want to have single ownership(Exclusive) of the resource. Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. A shared_ptr is a container for raw pointers.
The question has been clarified:
sorry I was not clear. I want the ownership to remain with original owner, the called function should only get reference to it, not ownership. Not looking for two smart pointer for the same object.
In that case, the solution is simply:
dynamic_cast<B&>(*my_unique_ptr)
Done. It throws if the cast doesn't succeed.
shared_ptr
For shared_ptr
there is std::dynamic_pointer_cast<>
(http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast)
unique_ptr
The simplest way would seem:
#include <memory> struct A { virtual ~A() = default; }; struct B : A { }; int main() { std::unique_ptr<A> pa(new B); std::unique_ptr<B> pb(dynamic_cast<B*>(pa.release())); // DO NOT DO THIS }
As the commenter rightfully points out, this may leak the object if the conversion failed. That's not very helpful.
A reason why the dynamic_unique_ptr_cast<>
doesn't exist might be that the unique_ptr
type doesn't erase the deleter. It could be hard/impossible to choose an appropriate delete for the target pointer type.
However, for simple cases, you could use something like this:
template <typename To, typename From, typename Deleter> std::unique_ptr<To, Deleter> dynamic_unique_cast(std::unique_ptr<From, Deleter>&& p) { if (To* cast = dynamic_cast<To*>(p.get())) { std::unique_ptr<To, Deleter> result(cast, std::move(p.get_deleter())); p.release(); return result; } return std::unique_ptr<To, Deleter>(nullptr); // or throw std::bad_cast() if you prefer } auto pb = dynamic_unique_cast<B>(std::move(pa));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With