プロが教える店舗&オフィスのセキュリティ対策術

try-catchでメモリ確保を含むクラスをスローした場合、デストラクタはどの時点で働くのか、教えてください。たとえば、↓の使いかたは大丈夫でしょうか?

【1】
try{
 throw(CError(100, "エラー情報"));
}catch(CError& err){
 //ここでerrを参照しても問題ないのでしょうか?
}

【2】
try{
 CError err(100, "エラー情報");
 throw(err); // (1)
}catch(CError& err){
 //ここでerrを参照しても問題ないのでしょうか?
 //まだデストラクタはちゃんと動作するのでしょうか?
 //catchが呼び出し元のメンバであったりしても大丈夫なのでしょうか?
}

宜しくお願いします。

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

コンパイラがオブジェクトのコピーを省略しているようです。
    • good
    • 0
この回答へのお礼

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

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

お礼日時:2008/05/06 15:42

#1です。


ちょっと説明不足でした。

throw test();

とすると、コピーコンストラクタが省略されるかどうかはコンパイラに依存します(最近は省略される方が多い)。
    • good
    • 0

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 がコピーされた後に破棄されますが。
環境依存なのかなあ?
    • good
    • 0
この回答へのお礼

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

お礼日時:2008/05/06 15:37

言葉で説明するより、実験した方がよいと思います。


例えば、

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

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

throw test();

のように例外オブジェクトを送出してみてください。
試してみれば、コピーコンストラクタを定義した意味も分かるはずです。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!