3

オブジェクトをカプセル化し、その有効期間を管理するための最良のアプローチは何ですか? 例: タイプBのオブジェクトを含み、それを単独で担当するクラスAがあります。

解決策 1 、 bオブジェクトのクローンを作成して、 Aのみがクリーンアップできるようにします。

class A
{
    B *b;
public:
    A(B &b)
    {
        this->b = b.clone();
    }

    ~A()
    {
        delete b; // safe
    }
};

解決策 2、渡されたオブジェクトを直接使用します。ここで二重解放の可能性があります。

class A
{
    B *b;
public:
    A(B *b)
    {
        this->b = b;
    }

    ~A()
    {
        delete b; // unsafe
    }
};

私の実際のケースでは、ソリューション #2 が最適です。ただし、文書化されていても、誰かがAの動作を知らない可能性があるため、これは悪いコードと見なされるのではないかと思います。これらのシナリオを考えることができます:

B *myB = new B();
A *myA = new A(myB);
delete myB; // myA contains a wild pointer now

または、

B *myB = new B();
A *firstA = new A(myB);
A *secondA = new A(myB); // bug! double assignment
delete firstA; // deletes myB, secondA contains a wild pointer now
delete secondA; // deletes myB again, double free

A の動作を適切に文書化すれば、これらの問題を無視できますか? 責任を宣言し、ドキュメントを読むのを他の人に任せるだけで十分ですか? これはコードベースでどのように管理されていますか?

4

6 に答える 6

5

本当に必要でない限り、自分で何かを削除することはありません。それはエラーにつながります。

スマートポインターはあなたの友達です。 std::auto_ptr<>あるオブジェクトが別のオブジェクトを所有し、範囲外になったときにそれを削除する責任がある場合は、あなたの友達です。 boost::shared_ptr<>(または、現在、std::tr1::shared_ptr<>) は、別のオブジェクトに複数のオブジェクトがアタッチされている可能性がある場合の友人であり、オブジェクトへの参照がなくなったときにオブジェクトを削除する必要があります。

したがって、ソリューション 1 を で使用するauto_ptrか、ソリューション 2 を で使用してくださいshared_ptr

于 2009-01-12T20:20:05.520 に答える
4

所有権のセマンティクスが可能な限りインターフェイスによって定義されるように、オブジェクトを定義する必要があります。David Thornley が指摘したように、 std::auto_ptr は、所有権の移転を示すために選択されるスマート ポインターです。次のようにクラスを定義します。

class A
{    
    std::auto_ptr<B> b;
public:    
    A(std::auto_ptr<B> b)    
    {
        this->b = b;
    }
    // Don't need to define this for this scenario
    //~A()
    //{ 
    //   delete b; // safe
    //}
};

std::auto_ptr の契約は割り当て = 所有権の譲渡であるため、コンストラクターは、渡された B へのポインターの所有権が A オブジェクトにあることを暗黙的に示します。実際、クライアントが構築後に A を構築するために使用した std::auto_ptr<B> を使用して何かを行おうとすると、クライアントが保持するポインターが無効になるため、操作は失敗します。

于 2009-01-12T20:28:13.353 に答える
2

オブジェクトが渡されたオブジェクトに対して単独で責任を負う場合、それを削除しても安全です。あなたが単独で責任を負うという主張よりも安全でない場合は、誤りです。それで、それはどれですか?インバウンドオブジェクトを削除することがインターフェースに記載されている場合、削除する必要があるオブジェクトを確実に受け取るのは呼び出し元の責任です。

于 2009-01-12T20:16:12.487 に答える
2

他の誰かが後で使用するコードを書いている場合は、これらの問題に対処する必要があります。この場合、単純な参照カウント (おそらくスマート ポインターを使用) を使用します。次の例を検討してください。

カプセル化クラスのインスタンスにオブジェクト B が割り当てられると、オブジェクトの B 参照カウンターを増やすメソッドが呼び出されます。カプセル化クラスが破棄されると、B は削除されませんが、代わりにメソッドが呼び出されて参照カウントが減少します。カウンターが 0 になると、オブジェクト B は破壊されます (つまり、オブジェクト自体も破壊されます)。このようにして、カプセル化クラスの複数のインスタンスが、オブジェクト B の単一のインスタンスで機能します。

主題の詳細:参照カウント

于 2009-01-12T20:11:42.997 に答える
1

A のクローンを作成していて、A1 と A2 の両方が B への参照を保持している場合、B の有効期間は A によって完全に制御されているわけではありません。さまざまな A 間で共有されています。クローン B により、A と B の間の 1 対 1 の関係が保証されます。 、これにより、生涯の一貫性を簡単に確保できます。

B のクローンを作成できない場合は、A が B の存続期間に関与しているという概念を破棄する必要があります。別のオブジェクトがさまざまな B を管理する必要があるか、参照カウントのようなメソッドを実装する必要があります。

参考までに、「クローン」という用語について考えるとき、それはディープ コピーを意味し、B もクローンします。クローンの後、2 つの As が互いに完全に切り離されることを期待しています。

于 2009-01-12T20:14:12.350 に答える
0

不必要に、または「安全のために」クローンを作成することはありません。

代わりに、ドキュメントを介して、またはスマートポインターによって、何かを削除するのが誰の責任であるかを知っています...たとえば、create何かをインスタンス化し、それへのポインターを返し、それを削除しない関数がある場合、それが不明確になるそのものがどこで誰によって削除されることになっている場合、createがネイキッド ポインターを返す代わりに、createの戻り値の型を、ある種のスマート ポインターに含まれるポインターを返すものとして定義することができます。

于 2009-01-12T20:15:33.050 に答える