119

shared_ptr派生型のをshared_ptr、基本型のをとる関数に渡すための最良の方法は何ですか?

shared_ptr不必要なコピーを避けるために、私は通常、参照によってsを渡します。

int foo(const shared_ptr<bar>& ptr);

しかし、私が次のようなことをしようとすると、これは機能しません

int foo(const shared_ptr<Base>& ptr);

...

shared_ptr<Derived> bar = make_shared<Derived>();
foo(bar);

使用できます

foo(dynamic_pointer_cast<Base, Derived>(bar));

しかし、これは2つの理由で最適ではないようです。

  • 単純なdynamic_cast派生からベースへのキャストには少し過剰に思えます。
  • 私が理解しているようdynamic_pointer_castに、関数に渡すポインターのコピー(一時的なものではありますが)を作成します。

より良い解決策はありますか?

後世のための更新:

ヘッダーファイルがないという問題であることが判明しました。また、ここで私がやろうとしていたことは、アンチパターンと見なされます。一般的、

  • オブジェクトの存続期間に影響を与えない(つまり、オブジェクトが関数の期間中有効である)関数は、単純な参照またはポインターを使用する必要がありますint foo(bar& b)

  • オブジェクトを消費する関数(つまり、特定のオブジェクトの最終ユーザー)は、unique_ptrby値を取る必要がありますint foo(unique_ptr<bar> b)。呼び出し元はstd::move、関数に値を入力する必要があります。

  • オブジェクトの存続期間を延長する関数は、shared_ptrby値を取る必要がありますint foo(shared_ptr<bar> b)循環参照を避けるための通常のアドバイスが適用されます。

詳細については、ハーブサッターの「基本に立ち返る」の話を参照してください。

4

4 に答える 4

60

これは、派生クラスでパブリック継承を指定するのを忘れた場合にも発生します。つまり、私のように次のように記述します。

class Derived : Base
{
};

それ以外の:

class Derived : public Base
{
};
于 2018-07-24T14:08:17.477 に答える
53

Baseとは共変ですがDerived、それらへの生のポインタはそれに応じて動作し、共変ではshared_ptr<Base>ありません。これは、この問題を処理するための正確で最も簡単な方法です。shared_ptr<Derived>dynamic_pointer_cast

編集: static_pointer_cast派生からベースにキャストするため、より適切です。これは安全で、ランタイムチェックを必要としません。以下のコメントを参照してください。)

ただし、foo()関数が存続期間の延長に参加したくない場合(または、オブジェクトの共有所有権に参加したくない場合)は、を受け入れて、に渡すときにconst Base&間接参照するのが最善です。shared_ptrfoo()

void foo(const Base& base);
[...]
shared_ptr<Derived> spDerived = getDerived();
foo(*spDerived);

余談ですが、shared_ptr型は共変ではないため、共変の戻り型をまたがる暗黙の変換の規則は、の型を返す場合には適用されませんshared_ptr<T>

于 2012-11-15T18:14:31.657 に答える
16

また#include、派生クラスの完全な宣言を含むヘッダーファイルのがソースファイルにあることを確認してください。

私はこの問題を抱えていました。にstd::shared<derived>キャストしませんstd::shared<base>。両方のクラスへのポインターを保持できるように両方のクラスを前方宣言しましたが#include、コンパイラーがなかったため、コンパイラーは一方のクラスがもう一方のクラスから派生したことを認識できませんでした。

于 2017-10-19T18:25:16.633 に答える
14

一生懸命頑張っているようですね。shared_ptrコピーするのは安いです。それがその目標の1つです。参照によってそれらを渡すことは実際には多くを達成しません。共有したくない場合は、生のポインタを渡します。

そうは言っても、これを行うには2つの方法があります。頭のてっぺんから考えることができます。

foo(shared_ptr<Base>(bar));
foo(static_pointer_cast<Base>(bar));
于 2012-11-15T18:30:21.073 に答える