ようこそ ゲスト さん、新規登録(無料)して気になる疑問を解決しませんか?

質問

質問者:pokapoka1980 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が呼び出し元のメンバであったりしても大丈夫なのでしょうか?
}

宜しくお願いします。
質問投稿日時:08/05/04 01:42
質問番号:3995992
この質問に対する回答は締め切られました。
最新から表示回答順に表示良回答のみ表示

回答

 

回答者:jacta #1です。
ちょっと説明不足でした。

throw test();

とすると、コピーコンストラクタが省略されるかどうかはコンパイラに依存します(最近は省略される方が多い)。
種類:回答
どんな人:専門家
自信:参考意見
回答日時:08/05/05 11:09
回答番号:No.4
この回答へのお礼この回答にお礼をつける(質問者のみ)

回答

良回答20pt

回答者:MASATO3 【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オブジェクトのデストラクタが呼び出される。

コンパイラがオブジェクトのコピーを省略しているようです。
種類:回答
どんな人:一般人
自信:参考意見
回答日時:08/05/05 10:04
回答番号:No.3
この回答へのお礼わかりやすくて、とても理解の助けになりました。
【2】の動作がいまいち納得がいきませんが、とりあえずコピーコンストラクタで間違えない作りであれば、大丈夫そうですね。

ありがとうございました。

回答

良回答10pt

回答者:koko_u_ 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 がコピーされた後に破棄されますが。
環境依存なのかなあ?
種類:アドバイス
どんな人:一般人
自信:参考意見
回答日時:08/05/04 23:54
回答番号:No.2
この回答へのお礼試してまで頂きありがとうございました。
デストラクタ普通に考える感じで呼ばれているのがわかりました。
感謝です。

回答

 

回答者:jacta 言葉で説明するより、実験した方がよいと思います。
例えば、

struct test
{
 test() { std::puts("test::test()"); }
 test(const test& other) { std::puts("test::test(other);"); }
 ~test() { std::puts("test::~test();"); }
};

といったクラスを定義して、

throw test();

のように例外オブジェクトを送出してみてください。
試してみれば、コピーコンストラクタを定義した意味も分かるはずです。
種類:アドバイス
どんな人:専門家
自信:参考意見
回答日時:08/05/04 02:25
回答番号:No.1
この回答へのお礼この回答にお礼をつける(質問者のみ)
最新から表示回答順に表示良回答のみ表示