2

ここで、例外をスローするコンストラクターに関する Michael Burr の素晴らしい要約を読みました: Will the below code cause memory leak in c++

私の質問は次のとおりです。コンストラクターから呼び出された関数によって例外がスローされた場合の動作は似ていますか? つまり、例外がスローされた場所で例外がキャッチされず、コンストラクターに到達し、さらにコンストラクターを呼び出した関数に到達する場合です。

そのオブジェクトのクラスに含まれるメンバー オブジェクトについて知りたいのですが、それらのデストラクタは呼び出されますか? より具体的には、私の場合は、boost::shared_ptr 型のメンバーに関するものです。

次の例を検討してください。

class A {
    A() { throw some_exception }
};

class B {
    B() { A a = new A(); }
};

class C {
    boost::shared_ptr<B> p2b;
    int i;
    int *pint;
    someclass objsomeclass;
    someclass* psomeclass;

public:
    C() {
        objsomeclass = someclass();
        psomeclass = new someclass();
        pint = new int(); 
        p2b(new B);
    }
};

void foo()
{
    C c();
}

main()
{
    foo();
}

p2a のデストラクタは呼び出されますか? このケースをカバーする適切で信頼できるリソースを教えていただければ幸いです。

4

1 に答える 1

3

コードを変更してコンパイルすると仮定すると、p2a(now p2b) のデストラクタが呼び出されます。これは、デフォルトで正常に構築されたためです。ただし、本体でリセットしようとするとC::C失敗するため、引き続き NULL が保持されます。

によって割り当てられたメモリnew Bは、スタックの巻き戻しプロセスによって自動的にクリーンアップされます。ただし、これらのメンバーpintには RAII を使用していないため、両方ともリークpsomeclass されます。

明確にするために、コードをステップ実行しましょう。

C::C() {
    objsomeclass = someclass();

    psomeclass = new someclass();
    pint = new int();

    p2b.reset(new B);
    /* in your code as posted, the call sequence is:
       new B (allocate sizeof B)
         -> B::B
           -> new A (allocate sizeof A)
             -> A::A which throws
           <- new A failed, so memory is freed
         <- B::B failed (initialized subobjects would be
            destroyed here, but there are none)
       new B failed, so memory is freed
    */
}

ご了承ください:

  • すべてのメンバーはすでにデフォルトで初期化されているため (初期化リストを使用しなかったため)、本体がC::C巻き戻されるとすべてが破棄されます。
  • psomeclasspintがスマート ポインターである場合、動的に割り当てられたメモリが解放されます。そうではないので、これはリークされています。

一般に、イニシャライザ リストと RAII を使用する方が適切です。

参考までに、この (非常に古い) 記事から始めてください: GOTW 66

于 2012-12-12T11:44:39.307 に答える