- ベストアンサー
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が呼び出し元のメンバであったりしても大丈夫なのでしょうか? } 宜しくお願いします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
【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オブジェクトのデストラクタが呼び出される。 コンパイラがオブジェクトのコピーを省略しているようです。
その他の回答 (3)
- jacta
- ベストアンサー率26% (845/3158)
#1です。 ちょっと説明不足でした。 throw test(); とすると、コピーコンストラクタが省略されるかどうかはコンパイラに依存します(最近は省略される方が多い)。
- koko_u_
- ベストアンサー率18% (459/2509)
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 がコピーされた後に破棄されますが。 環境依存なのかなあ?
お礼
試してまで頂きありがとうございました。 デストラクタ普通に考える感じで呼ばれているのがわかりました。 感謝です。
- jacta
- ベストアンサー率26% (845/3158)
言葉で説明するより、実験した方がよいと思います。 例えば、 struct test { test() { std::puts("test::test()"); } test(const test& other) { std::puts("test::test(other);"); } ~test() { std::puts("test::~test();"); } }; といったクラスを定義して、 throw test(); のように例外オブジェクトを送出してみてください。 試してみれば、コピーコンストラクタを定義した意味も分かるはずです。
お礼
わかりやすくて、とても理解の助けになりました。 【2】の動作がいまいち納得がいきませんが、とりあえずコピーコンストラクタで間違えない作りであれば、大丈夫そうですね。 ありがとうございました。