如何用unique_ptr执行动态_cast?

问题描述 投票:26回答:4

我有一个类的层次结构如下。

class BaseSession : public boost::enable_shared_from_this<BaseSession>
class DerivedSessionA : public BaseSession
class DerivedSessionB : public BaseSession

在派生类函数中,我经常调用这样的函数。

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

因为我的工作是 shared_ptr 来管理会话,本来效果不错。最近,我发现我使用的 shared_ptr 并不是这种情况下的最佳选择。这是因为这些session是单子对象,每个客户端维护一个socket。如果套接字被重新连接,过去的session副本就会变成僵尸。

作为变通办法,我开始将 shared_ptr 通过参考而不是复制。这样就解决了僵尸问题。

理想情况下,我觉得我应该使用 unique_ptr 来存储会话,然后将引用传递给其他函数。这就打开了一扇门。

我如何将一个基类 unique_ptr 派生类 unique_ptr 对象?梢运? unique_ptr 下面一行的版本?

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

我只是想要一个会话对象的副本,其他的都应该是引用。

c++ boost smart-pointers unique-ptr dynamic-cast
4个回答
14
投票

除非你想转移你的 std::unique_ptr<T>,你的函数应该取指针或引用到 T.

所以签署 Func 应该是 Func(DerivedSessionA*)

然后你的调用可能看起来像。

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

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

或者像你所说的那样直接从一个方法中调用它。BaseSession:

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

30
投票

最新情况

这个问题已经澄清了。

对不起,我没说清楚 我希望所有权仍然是原所有者的,被调用的函数应该只获得对它的引用,而不是所有权。而不是找同一个对象的两个智能指针。

在这种情况下,解决办法很简单。

dynamic_cast<B&>(*my_unique_ptr)

Done. 如果施放不成功,它就会抛出。


铸造 shared_ptr

对于 shared_ptrstd::dynamic_pointer_cast<> (http:/en.cppreference.comwcppmemoryshared_ptrpointer_cast。)

铸造 unique_ptr

似乎是最简单的方法。

#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
}

正如评论员所指出的那样,如果转换失败,这可能会泄露对象。这就是 很有帮助。

的一个原因。dynamic_unique_ptr_cast<> 不存在的可能是 unique_ptr 类型的删除器不会被删除。可能很难为目标指针类型选择一个合适的删除器。

然而,对于简单的情况,你可以使用这样的东西。

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));

1
投票

这是boost的dynamic_pointer_cast. 这个想法很简单(但是忽略dealer)。

//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 );
}

-1
投票

只需使用 std::unique_ptr<>::get() 方法。

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

如果 shared_from_this() 有这个原型。

std::unique_ptr<BaseSession>& shared_from_this();
© www.soinside.com 2019 - 2024. All rights reserved.