57

C++11 では、 a を使用しshared_ptr<>て、オブジェクトまたは変数との所有関係を確立し、weak_ptr<>そのオブジェクトを所有されていない方法で安全に参照できます。

unique_ptr<>オブジェクトまたは変数との所有関係を確立するために使用することもできます。しかし、所有していない他のオブジェクトもそのオブジェクトを参照したい場合はどうなるでしょうか? weak_ptr<>この場合は役に立ちません。生のポインターは便利ですが、さまざまな欠点があります (たとえば、 nullptr に自動的に初期化できますが、これは型と一致しない手法によって実現されstd::*_ptr<>ます)。

weak_ptr<>を介して所有されているオブジェクトへの非所有参照に相当するものは何unique_ptr<>ですか?

これは、私が取り組んでいるゲームの何かに似た明確な例です。

class World
{
public:

    Trebuchet* trebuchet() const { return m_trebuchet.get(); }

private:
    std::unique_ptr< Trebuchet > m_trebuchet;
};

class Victim
{
public:
    Victim( Trebuchet* theTrebuchet ) : m_trebuchet( theTrebuchet ) {}

    ~Victim()
    {
        delete m_trebuchet;     // Duh. Oops. Dumb error. Nice if the compiler helped prevent this.
    }

private:

    Trebuchet* m_trebuchet;    // Non-owning.
};

shared_ptr< Victim > createVictim( World& world )
{
    return make_shared< Victim >( world.trebuchet() );
}

ここでは、生のポインターを使用して、他の場所で所有されているオブジェクトとの非所有関係を維持しunique_ptr<>ます。しかし、生は私たちができる最善のことですか?

希望は、次のようなポインターの型です。

  • 他の最新のポインター型のように見えます。例std::raw_ptr<T>
  • 生のポインターを置き換えて、全体で最新のポインター型を使用するコードベースが(大まかに)を検索してすべてのポインターを見つけることができるようにします。_ptr<
  • nullptr に自動初期化します。

したがって:

int* p;                  // Unknown value.
std::raw_ptr< int > p;   // null.

この型は現在 C++ に既に存在していますか、それは将来的に提案されていますか、それとも Boost などで広く利用可能な別の実装ですか?

4

8 に答える 8

38

の「通知」動作にshared_ptrは、参照カウント制御ブロックの参照カウントが必要です。shared_ptrの参照カウント制御ブロックは、これに別の参照カウントを使用します。weak_ptrインスタンスはこのブロックへの参照を維持し、それ自体が参照カウント制御ブロックの編集weak_ptrを防ぎます。delete指示されたオブジェクトは、強いカウントがゼロになったときに呼び出されるデストラクタを持ち (deleteそのオブジェクトが格納されていたメモリのイオンになる場合とそうでない場合があります)、制御ブロックはdelete弱い参照カウントがゼロになった場合にのみ ed になります。 .

unique_ptrの信条は、プレーンなポインターのオーバーヘッドがゼロであることです。参照カウント制御ブロックを (-ish セマンティクスをサポートするために) 割り当てて維持するとweak_ptr、その原則が破られます。その説明の動作が必要な場合は、オブジェクトへの他の参照が非所有であっても、共有セマンティクスが本当に必要です。その場合でも、オブジェクトが破棄されているかどうかの状態の共有が行われています。

一般的な非所有参照が必要で、通知が不要な場合は、unique_ptr.


編集:

あなたの例の場合、ではなくVictimを要求する必要があるようです。次に、問題のオブジェクトの所有者が誰であるかは明らかです。Trebuchet&Trebuchet*

class World
{
public:

    Trebuchet& trebuchet() const { return *m_trebuchet.get(); }

private:
    std::unique_ptr< Trebuchet > m_trebuchet;
};

class Victim
{
public:
    Victim( Trebuchet& theTrebuchet ) : m_trebuchet( theTrebuchet ) {}

    ~Victim()
    {
        delete m_trebuchet;     // Compiler error. :)
    }

private:

    Trebuchet& m_trebuchet;    // Non-owning.
};

shared_ptr< Victim > createVictim( World& world )
{
    return make_shared< Victim >( world.trebuchet() );
}
于 2013-07-08T22:09:21.937 に答える
8

unique_ptrの非所有アナログは、プレーンな C ポインターです。何が違うのか - C ポインターは、ポイントされたデータがまだアクセス可能かどうかを知りません。weak_ptr一方、そうです。rawしかし、追加のオーバーヘッドなしでデータの有効性を認識しているポインターにポインターを置き換えることは不可能です(そしてweak_ptrそのオーバーヘッドはあります)。これは、C スタイルのポインターが、unique_ptr.

于 2013-07-08T22:25:53.417 に答える
3
boost::optional<Trebuchet&>

Billy ONeal が彼の回答で指摘したTrebuchet&ように、ポインターの代わりに a を渡したいと思うでしょう。参照の問題は、 a を渡すことができないことであり、 a と同等のものを持つ方法を提供しnullptrます。boost::optional の詳細はこちら: http://www.boost.org/doc/libs/1_54_0/libs/optional/doc/html/boost_optional/detailed_semantics.htmlboost::optionalnullptr

この質問も参照してください: boost::optional<T&> vs T*

注:std::optional<T>は C++14 に組み込む予定ですがstd::optional<T&>、現在の C++14 ドラフトには含まれていない別の提案です。詳細はこちら: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3672.html

于 2013-07-12T00:12:00.083 に答える
1

shared_ptr、weak_ptr、および unique_ptr を使用する新しい C++ の世界では、トレビュシェットのように、生のポインターまたは参照を使用して、オブジェクトへの長期間有効な参照を格納するべきではありません。代わりに、World はトレビュシェットへの shared_ptr を持つ必要があり、Victim は、ワールドがなくなった場合にトレビュシェットが被害者に留まる必要があるかどうかに応じて、shared_ptr または weak_ptr のいずれかを格納する必要があります。weak_ptr を使用すると、ポインターがまだ有効かどうか (つまり、ワールドがまだ存在するかどうか) を知ることができますが、生のポインターまたは参照でこれを行う方法はありません。

unique_ptr を使用すると、World インスタンスのみがトレビュシェットを所有することを宣言します。World クラスのクライアントは、「get」メソッドを呼び出すことで World オブジェクトのトレビュシェットを使用できますが、メソッドの使用が終了したときに、メソッドによって返された参照またはポインターを保持するべきではありません。代わりに、「get」メソッドを呼び出して、トレビュシェットを使用するたびに「借用」する必要があります。

上記は、shared_ptr のオーバーヘッドを回避するために、将来の使用のために参照または生のポインターを格納する必要がある場合があると言われています。しかし、これらのインスタンスはほとんどないため、トレビュシェットを所有する World オブジェクトがなくなった後は、ポインターまたは参照を使用しないことを完全に確認する必要があります。

于 2013-07-10T00:03:21.260 に答える