web-dev-qa-db-ja.com

このstd :: shared_ptr

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

クラス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_ptrthis)を子に渡す方法です。

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

77
Icarus

この目的のために _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_によって所有されている必要があります。これは、そのようなオブジェクトをスタック上に作成できなくなり、generalallyがコンストラクタまたはデストラクタ内から.shared_from_this()を呼び出せないことを意味します。

142
yuri kilochek

デザインにはいくつかの問題がありますが、それはスマートポインターに対する誤解に起因しているようです。

スマートポインターは、所有権を宣言するために使用されます。両方の親がすべての子を所有しているだけでなく、各子がその親を所有していることを宣言することにより、これを破ります。両方とも真実ではありえません。

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

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

7
Let_Me_Be