关于c ++:如何使用unique_ptr执行dynamic_cast?

How to do perform a dynamic_cast with a unique_ptr?

我有一个类层次结构,如下所示:

1
2
3
class BaseSession : public boost::enable_shared_from_this<BaseSession>
class DerivedSessionA : public BaseSession
class DerivedSessionB : public BaseSession

在派生类函数中,我经常调用如下函数:

1
Func(boost::dynamic_pointer_cast<DerivedSessionA>(shared_from_this()));

因为我和shared_ptr合作管理会议,所以工作很顺利。最近,我发现我使用shared_ptr并不适合这个案例。这是因为这些会话是单例对象,每个客户端维护一个套接字。如果重新连接套接字,会话副本将变成僵尸。

为了解决这个问题,我开始通过引用而不是副本来传递shared_ptr。这解决了僵尸问题。

理想情况下,我觉得应该使用unique_ptr来存储会话,然后传递对其他函数的引用。打开了一整罐虫子。

如何将基类unique_ptr对象强制转换为派生类unique_ptr对象?以下行的unique_ptr版本是什么?

1
Func(boost::dynamic_pointer_cast<DerivedSessionA>(shared_from_this()));

我只需要会话对象的一个副本,其他所有内容都应该是引用。


更新

问题已经澄清:

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.

在这种情况下,解决方案很简单:

1
dynamic_cast<B&>(*my_unique_ptr)

完成。如果施法不成功,它就会抛出。

铸造shared_ptr

对于shared_ptrstd::dynamic_pointer_cast<>(http://en.cppreference.com/w/cpp/memory/shared-ptr/pointer-cast)

铸造unique_ptr

最简单的方法是:

1
2
3
4
5
6
7
8
9
10
11
#include <memory>

struct A { virtual ~A() = default; };
struct B : A { };

int main()
{
    std::unique_ptr<A> pa(new B);

    std::unique_ptr pb(dynamic_cast<B*>(pa.release())); // DO NOT DO THIS
}

正如评论者正确指出的那样,如果转换失败,这可能会泄漏对象。那不是很有帮助。

dynamic_unique_ptr_cast<>不存在的一个原因可能是unique_ptr类型没有删除删除程序。可能很难/不可能为目标指针类型选择适当的删除。

但是,对于简单的情况,您可以使用如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
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(std::move(pa));


除非您想转移您的std::unique_ptr的所有权,否则您的函数应该使用指向T的指针或引用。

因此,Func的签名应该类似于Func(DerivedSessionA*)的签名。

然后你的电话看起来像:

1
2
3
std::unique_ptr<BaseSession> ptr; // Initialize it with correct value

Func(dynamic_cast<DerivedSessionA*>(ptr.get()));

或者您似乎直接从BaseSession中的方法调用它:

1
Func(dynamic_cast<DerivedSessionA*>(this));


只需使用std::unique_ptr<>::get()方法获取存储的指针:

1
Func(dynamic_cast<DerivedSessionA*>(shared_from_this().get()))

如果shared_from_this()有这个原型:

1
std::unique_ptr<BaseSession>& shared_from_this();