1

オブジェクトを構築するときに例外が発生した場合、いくつかの興味深い動作を見つけました。

class bookentry
{
public:
    bookentry(){
      t1.reset(new test1);       //0 
      test1 *t11 = new test1;    //1
      test2 *t22 = new test2;    //2
      throw 1;                   //3
    }
protected:
private:
  auto_ptr<test1> t1;
  auto_ptr<test2> t2;
};

私がテストしたものから:

test2 のコンストラクター (#2)から例外をスローすると、

  1. t1 : 完全に破棄されます。つまり、t1 のデストラクタが呼び出され、メモリが解放されます。
  2. t11 : 破棄されることはありません (t11 のデストラクタを呼び出したり、メモリを解放したりしません)。
  3. t22 : これは面白い部分です。t22 のデストラクタは呼び出されませんが、t22 のメモリは解放されます!

bookentry のコンストラクター (#3)から例外をスローすると、今回は少し異なります: t22は決して破棄されません (t22 のデストラクタを呼び出すことも、メモリを解放することもありません)。t11 は上記と同じです。

#2の文と混同しています

test2 *t22 = 新しい test2; //2

クラスコンストラクターから例外をスローすると、 new 式は対応する削除が呼び出されることを確認します、その例外の前に new 式を介して完全に作成されたオブジェクトはリークされます (t11、または t11 および t22 をスローした場合) #3の例外)。

したがって、以下のようなコードを書き、5 番目のオブジェクトの構築に失敗した場合:

test2 *t2s = 新しい test2[10];

次に、少し安全なようです:

  1. すでに構築されたオブジェクトは破棄されます。
  2. メモリが解放されます。

私の質問は、これは標準的な C++ の動作ですか? msvc 2012 と gcc 4.4.6 をテストしたところ、どちらもそのようなメカニズムを実装しているように見えます。

私の質問をより明確にするために編集してください:

場合によっては、他の通常の関数で t1.reset(new test1) [コードの #1 を参照] のようなコードを記述する必要があります。そのような場合、コンストラクターから例外がスローされた場合。プログラムの状態を判断するにはどうすればよいですか? メモリリークはありますか?

私のテストでは、これらがそのような場合にメモリリークがないことを確認していますが、それは標準的な C++ の動作ですか?

4

1 に答える 1

3

ルールは単純です:
そのスコープ内で完全に作成されたすべてのオブジェクトは破棄されます。上記のルールは、動的ストレージ (で割り当てられた
) に割り当て られたオブジェクトを指す生のポインターには適用されません。それらは明示的にdである必要があります。を使用すると、リソース管理を明示的に所有し、 を呼び出してリソースを解放するのはあなたの仕事であり、コンパイラはそれを行いません。newdeletenewdelete


よく読んだ:

コンストラクターの失敗 - Herb Sutter


C++ でリソースを管理する最善の方法は、RAII とスマート ポインターを使用することです。コンストラクターではさらにそうです。生のポインターを使用する代わりに、それらをスマート ポインターでラップするだけで、そのような例外が発生した場合にオブジェクトのリソース管理を自動的に実行します。auto_ptr生のポインターとは対照的に、コード例で使用したときに、この力を体験したばかりです。

于 2013-05-08T05:53:11.263 に答える