• ベストアンサー

try{}catch(){}とデストラクタの関係を教えてください。

try-catchでメモリ確保を含むクラスをスローした場合、デストラクタはどの時点で働くのか、教えてください。たとえば、↓の使いかたは大丈夫でしょうか? 【1】 try{  throw(CError(100, "エラー情報")); }catch(CError& err){  //ここでerrを参照しても問題ないのでしょうか? } 【2】 try{  CError err(100, "エラー情報");  throw(err); // (1) }catch(CError& err){  //ここでerrを参照しても問題ないのでしょうか?  //まだデストラクタはちゃんと動作するのでしょうか?  //catchが呼び出し元のメンバであったりしても大丈夫なのでしょうか? } 宜しくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • MASATO3
  • ベストアンサー率60% (27/45)
回答No.3

【1】【2】どちらの場合も問題がありません。 コンパイラが必要に応じてerrオブジェクトのコピーを作成します。 デストラクタが呼び出されるタイミングはコンパイラに依存するところもあると思いますが、 例えばVC7.1では【2】は以下のように動作します。 (1) errオブジェクトのコンストラクタが呼び出される (2) CErrorクラスのテンポラリオブジェクト(以下a)のコピーコンストラクタが呼び出される。 (3) errオブジェクトのデストラクタが呼び出される (4) catch文まで到達 (5) aオブジェクトのデストラクタが呼び出される。 VC7.1では、【1】は以下のように動作します。 (1) errオブジェクトのコンストラクタが呼び出される (2) catch文まで到達 (3) errオブジェクトのデストラクタが呼び出される。 コンパイラがオブジェクトのコピーを省略しているようです。

pokapoka1980
質問者

お礼

わかりやすくて、とても理解の助けになりました。 【2】の動作がいまいち納得がいきませんが、とりあえずコピーコンストラクタで間違えない作りであれば、大丈夫そうですね。 ありがとうございました。

その他の回答 (3)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

#1です。 ちょっと説明不足でした。 throw test(); とすると、コピーコンストラクタが省略されるかどうかはコンパイラに依存します(最近は省略される方が多い)。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.2

throw Test(); で生成と同時に例外を投げると、 コピーコンストラクタが呼ばれないように見えますね。 ----------- 使用したコード --------- struct Test {  // 省略 }; int main() {  try {   cerr << "throw!" << endl;   throw Test();  }  catch (Test const& test) {   cerr << "catch!" << endl;  }  return 0; } ---------- 実行した結果 ------------- $ ./test throw! Test::Test() catch! Test::~Test() ---------- 環境 --------------------- FreeBSD 6.3-RELEASE-p2 g++ 3.4.6 ------------------------------------- throw Test(); の箇所を Test test; throw test; にすると、try ブロックで test がコピーされた後に破棄されますが。 環境依存なのかなあ?

pokapoka1980
質問者

お礼

試してまで頂きありがとうございました。 デストラクタ普通に考える感じで呼ばれているのがわかりました。 感謝です。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.1

言葉で説明するより、実験した方がよいと思います。 例えば、 struct test {  test() { std::puts("test::test()"); }  test(const test& other) { std::puts("test::test(other);"); }  ~test() { std::puts("test::~test();"); } }; といったクラスを定義して、 throw test(); のように例外オブジェクトを送出してみてください。 試してみれば、コピーコンストラクタを定義した意味も分かるはずです。