次のようなクラス階層があります。
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
の使用がこの場合に最適ではないことを発見しました。これは、これらのセッションがクライアントごとに1つのソケットを保持するシングルトンオブジェクトであるためです。ソケットが再接続されると、セッションコピーがゾンビになるために使用されます。
回避策として、コピーではなく参照によってshared_ptr
を渡し始めました。これにより、ゾンビの問題が解決しました。
理想的には、unique_ptr
を使用してセッションを保存し、他の関数への参照を渡す必要があると感じました。それはワームの缶全体を開きました。
基本クラスunique_ptr
オブジェクトを派生クラスunique_ptr
オブジェクトにキャストするにはどうすればよいですか?次の行のunique_ptr
バージョンとは何ですか?
Func(boost::dynamic_pointer_cast<DerivedSessionA>(shared_from_this()));
セッションオブジェクトのコピーが1つだけ必要です。それ以外はすべて参照する必要があります。
_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));
_
質問が明確になりました:
申し訳ありませんが明確ではありませんでした。所有権は元の所有者のままにしておきたいのですが、呼び出された関数は所有権ではなく、その参照のみを取得する必要があります。同じオブジェクトの2つのスマートポインターを探していません。
その場合の解決策は次のとおりです。
dynamic_cast<B&>(*my_unique_ptr)
完了キャストが成功しない場合にスローされます。
shared_ptr
にとって shared_ptr
有る std::dynamic_pointer_cast<>
( http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_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
}
コメント者が正しく指摘しているように、変換が失敗した場合、オブジェクトがリークする可能性があります。それはnot非常に有用です。
dynamic_unique_ptr_cast<>
が存在しない場合、unique_ptr
typeは削除者を消去しません。ターゲットポインタータイプに適切な削除を選択するのは難しい/不可能な場合があります。
ただし、単純な場合には、次のようなものを使用できます。
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));
これは、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 );
}