これのstd :: shared_ptr


101

私は現在、スマートポインターの使用方法を学習しようとしています。しかし、いくつかの実験を行っているときに、満足のいく解決策を見つけることができない次の状況を発見しました。

クラスAのオブジェクトがクラスB(子)のオブジェクトの親であるとしますが、両方がお互いを知っている必要があります。

class A;
class B;

class A
{
public:
    void addChild(std::shared_ptr<B> child)
    {
        children->push_back(child);

        // How to do pass the pointer correctly?
        // child->setParent(this);  // wrong
        //                  ^^^^
    }

private:        
    std::list<std::shared_ptr<B>> children;
};

class B
{
public:
    setParent(std::shared_ptr<A> parent)
    {
        this->parent = parent;
    };

private:
    std::shared_ptr<A> parent;
};

問題は、クラスAのオブジェクトstd::shared_ptrがそれ自体の(this)をその子にどのように渡すことができるかです。

Boost共有ポインターのソリューション(Getting boost::shared_ptrfor forthis)はありますが、std::スマートポインターを使用してこれを処理する方法は?


2
他のツールと同様に、適切な場合に使用する必要があります。あなたがやっていることにスマートポインターを使用することはできません
YePhIcK '29

同様にブーストします。こちらをご覧ください
juanchopanza

1
これは、その抽象化のレベルでの問題です。「これ」がヒープ上のメモリを指していることさえわかりません。
Vaughn Cato、2012

まあ、言語はしませんが、あなたはします。何がどこにあるかを追跡している限り、大丈夫です。
Alex

回答:


168

std::enable_shared_from_thisこの目的のためだけにあります。それを継承し.shared_from_this()、クラスの内部から呼び出すことができます。また、ここでは、リソースリークを引き起こす可能性のある循環依存関係を作成しています。これはを使用して解決できますstd::weak_ptr。したがって、コードは次のようになります(子が親の存在に依存し、その逆ではないと想定)。

class A;
class B;

class A
    : public std::enable_shared_from_this<A>
{
public:
    void addChild(std::shared_ptr<B> child)
    {
        children.push_back(child);

        // like this
        child->setParent(shared_from_this());  // ok
        //               ^^^^^^^^^^^^^^^^^^
    }

private:     
    // note weak_ptr   
    std::list<std::weak_ptr<B>> children;
    //             ^^^^^^^^
};

class B
{
public:
    void setParent(std::shared_ptr<A> parent)
    {
        this->parent = parent;
    }

private:
    std::shared_ptr<A> parent;
};

ただし、呼び出しに.shared_from_this()は呼び出しの時点でthisが所有している必要があることに注意してくださいstd::shared_ptr。これは、そのようなオブジェクトをスタック上に作成できなくなり、通常.shared_from_this()、コンストラクターまたはデストラクター内から呼び出すことができないことを意味します。


1
あなたの説明と私の循環依存問題を指摘してくれてありがとう。
イカルス

@Deduplicatorどういう意味ですか?
2015年

shared_ptrdefault-constructedに基づいてを構築してみて、shared_ptrそれをポイントしたいものは何でも…
Deduplicator

1
@Deduplicatorは、私の駄洒落ではなく、無意味な共有ポインタです。このコンストラクターは、管理対象オブジェクトまたはそのベースのメンバーへのポインターと共に使用することを目的としています。とにかくあなたのポイントは何ですか(すみません)?これらの非所有shared_ptrは、この質問には関係ありません。shared_from_thisの前提条件shared_ptrは、呼び出しの時点で、オブジェクトが(単に指し示されているだけでなく)所有されている必要があることを明確に述べています。
ユーリキロチェク2015年

1
@kazareyによる所有権shared_ptrは呼び出しの時点で必要ですが、典​​型的な使用パターン(つまり、など)shared_ptr<Foo> p(new Foo());ではshared_ptr、オブジェクトが完全に構築された後でのみ、オブジェクトの所有権を想定します。でshared_ptr初期化されたコンストラクタで作成し、thisそれをローカル以外の場所(たとえば、参照引数)に格納することで、これを回避できます。これにより、コンストラクタが完了したときに死にません。ただし、この複雑なシナリオが必要になることはほとんどありません。
ユーリキロチェク2016

9

設計にいくつかの問題があります。それは、スマートポインターの誤解から生じているようです。

スマートポインタは、所有権を宣言するために使用されます。これは、両方の親がすべての子を所有していること、および各子がその親を所有していることを宣言することによって破られています。どちらも当てはまりません。

また、あなたは弱いポインタを返しています getChild()。そうすることで、呼び出し側が所有権を気にする必要がないことを宣言しています。これは非常に制限される可能性がありますが、そうすることによって、弱いポインタがまだ保持されている間、問題の子が破棄されないことを確認する必要があります。スマートポインタを使用する場合は、それ自体でソートされます。 。

そして最後に。通常、新しいエンティティを受け入れるときは、通常、生のポインタを受け入れる必要があります。スマートポインターは、親間で子を交換するための独自の意味を持つことができますが、一般的な使用法では、生のポインターを受け入れる必要があります。


スマートポインターの理解を明確にする必要があるようです。指摘いただきありがとうございます。
イカルス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.