例外をスローするC ++クラスのDestructorは呼び出されますか?
-
01-10-2019 - |
質問
私がこのようなクラスを持っているとします:
#include <iostream>
using namespace std;
class Boda {
private:
char *ptr;
public:
Boda() {
ptr = new char [20];
}
~Boda() {
cout << "calling ~Boda\n";
delete [] ptr;
}
void ouch() {
throw 99;
}
};
void bad() {
Boda b;
b.ouch();
}
int main() {
bad();
}
その破壊者のようです ~Boda
呼び出されることはありません ptr
リソースは決して解放されません。
これがプログラムの出力です:
terminate called after throwing an instance of 'int'
Aborted
だから、私の質問に対する答えはそうです No
.
しかし、例外がスローされたとき、スタックは巻き戻されたと思いましたか?なぜそうしなかったのか Boda b
私の例ではオブジェクトが破壊されますか?
このリソースの問題を理解するのを手伝ってください。将来、より良いプログラムを書きたいです。
また、これはいわゆるものです RAII
?
ありがとう、ボダシド。
解決
例外がどこにもキャッチされていない場合、C ++ランタイムは、スタックの巻き戻しやデストラクタを呼び出すことなく、プログラムを終了するために直接移動できます。
ただし、通話の周りにトライキャッチブロックを追加した場合 bad()
, 、あなたはそれのためのデストラクタを見るでしょう Boda
呼び出されるオブジェクト:
int main() {
try {
bad();
} catch(...) { // Catch any exception, forcing stack unwinding always
return -1;
}
}
raii 動的(ヒープ)割り当てられたメモリは、オブジェクトが破壊されたときにそれを扱うオブジェクトが自動的に(スタック)割り当てられたオブジェクトによって常に所有されることを意味します。これは、通常のリターンによるものであろうと例外によるものであろうと、自動化されたオブジェクトが範囲外に出るときに破壊者が呼び出されるという保証に依存しています。
通常、このコーナーケースの動作は、通常RAIIに関しては問題ではありません。通常、デストラクタを実行したい主な理由はメモリを解放することであり、とにかくプログラムが終了するとすべてのメモリがOSに戻されます。ただし、ディスク上のロックファイルを削除するなど、破壊者がより複雑なことをしている場合、クラッシュ時にデストラクタと呼ばれるプログラムが違いを生む場合は、ラップしたい場合があります。 main
すべてをキャッチするトライキャッチブロックで(とにかく例外でのみ終了するだけです)、終了する前にスタックが常にくつろぐことを確認します。
他のヒント
コンストラクターで例外が発生した場合、破壊者は実行されません。
例外が例外のような別の方法で提起された場合、必要に応じて(例外がどこかで処理される場合)実行されます。しかし、プログラムが終了すると、ここではデストラクタを呼び出す必要はなく、動作はコンパイラの依存しています...
のアイデア RAII
コンストラクターがRessourcesを割り当て、Destructorがそれらを自由に割り当てることです。コンストラクターで例外が発生した場合、割り当てられていない場所を知る簡単な方法はありません(例外が発生したコンストラクターの正確な場所に依存します)。また、コンストラクターが失敗した場合、例外を提起するためにそれを発信者に言う唯一の方法であることを覚えておく必要があります と 割り当てられたメモリは、割り当てられていないかのように解放されます(スタック巻き戻し、またはヒート割り当てメモリのいずれか)。
解決策は明らかです。コンストラクター内で例外が発生する可能性がある場合は、必要に応じてキャッチして無料割り当てをキャッチする必要があります。実際には、Destructorを使用した複製コードである可能性がありますが、それは大きな問題ではありません。
Destructorでは、スタックの巻き戻しで大きなトラブルにつながる可能性があるため、例外を提起するべきではありません。
他の方法では、必要に応じて例外を使用しますが、どこかでそれらを処理することを忘れないでください。未処理の覚醒は、例外ではないよりも悪いかもしれません。いくつかの小さなエラーの例外を処理しないいくつかのプログラムを知っています...そして、警告を発するだけのエラーのためにクラッシュします。
ストリームを洗い流してみてください - デストラクタが実際に呼ばれていることがわかります。
cout << "calling ~Boda" << endl;
I/Oのバッファリングは、プログラムの終了が実際の出力の前に削減されるポイントまでプリントアウトを遅らせます。
編集:
上記は保持されます 処理された例外. 。と 未処理の例外 標準では、スタックがゆったりとしていないかどうかは指定されていません。参照してください これはとても質問です.