C++ 如何使用 unique_ptr 执行 dynamic_cast?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26377430/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to do perform a dynamic_cast with a unique_ptr?
提问by Sharath
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.
由于我正在与shared_ptr
管理会话一起工作,因此工作正常。最近,我发现我shared_ptr
对这种情况的使用并不是最佳选择。这是因为这些会话是单例对象,每个客户端维护一个套接字。如果重新连接套接字,会话副本将变成僵尸。
As workaround, I started passing shared_ptr
by reference rather than copies. This solved the zombie problem.
作为解决方法,我开始通过shared_ptr
引用而不是副本传递。这解决了僵尸问题。
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.
理想情况下,我觉得我应该使用它unique_ptr
来存储会话,然后将引用传递给其他函数。这打开了一整罐蠕虫。
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?
如何将基类unique_ptr
对象转换为派生类unique_ptr
对象?unique_ptr
以下行的版本是什么?
Func(boost::dynamic_pointer_cast<DerivedSessionA>(shared_from_this()));
I just want one copy of the session object, everything else should be reference.
我只想要会话对象的一份副本,其他所有内容都应该是参考。
采纳答案by Jarod42
Unless you want to transfer ownership of your std::unique_ptr<T>
, your function should take pointer or reference to T
.
除非您想转移您的 所有权,否则您std::unique_ptr<T>
的函数应该采用指向T
.
So signature of Func
should be something like Func(DerivedSessionA*)
所以签名Func
应该是这样的Func(DerivedSessionA*)
and then your call may look like:
然后你的电话可能看起来像:
std::unique_ptr<BaseSession> ptr; // Initialize it with correct value
Func(dynamic_cast<DerivedSessionA*>(ptr.get()));
Or as you seems to call it directly from a method in BaseSession
:
或者,您似乎直接从 中的方法调用它BaseSession
:
Func(dynamic_cast<DerivedSessionA*>(this));
回答by sehe
Update
更新
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.
完成。如果演员不成功,它会抛出。
Casting shared_ptr
铸件 shared_ptr
For shared_ptr
there is std::dynamic_pointer_cast<>
(http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast)
因为shared_ptr
有std::dynamic_pointer_cast<>
(http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast)
Casting unique_ptr
铸件 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 notvery 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.
dynamic_unique_ptr_cast<>
不存在的原因可能是该unique_ptr
类型不会删除删除器。为目标指针类型选择适当的删除可能很困难/不可能。
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));
回答by xinnjie
This is dynamic_pointer_cast of boost. The idea is quite simple(but ignore the deleter).
这是 boost 的 dynamic_pointer_cast。这个想法很简单(但忽略删除器)。
//dynamic_pointer_cast overload for std::unique_ptr
template<class T, class U> std::unique_ptr<T> dynamic_pointer_cast( std::unique_ptr<U> && r ) BOOST_SP_NOEXCEPT
{
(void) dynamic_cast< T* >( static_cast< U* >( 0 ) );
BOOST_STATIC_ASSERT_MSG( boost::has_virtual_destructor<T>::value, "The target of dynamic_pointer_cast must have a virtual destructor." );
T * p = dynamic_cast<T*>( r.get() );
if( p ) r.release();
return std::unique_ptr<T>( p );
}
回答by Stefano Buora
Simply get the stored pointer using the std::unique_ptr<>::get()
method:
只需使用以下std::unique_ptr<>::get()
方法获取存储的指针:
Func(dynamic_cast<DerivedSessionA*>(shared_from_this().get()))
that if shared_from_this()
has that prototype:
如果shared_from_this()
有那个原型:
std::unique_ptr<BaseSession>& shared_from_this();