インタビューでこの質問に直面する前のある日。だからただ私を案内してください。
c++でコンストラクタから例外がスローされた場合、初期化されたリソースをクリーンアップする方法は?
インタビューでこの質問に直面する前のある日。だからただ私を案内してください。
c++でコンストラクタから例外がスローされた場合、初期化されたリソースをクリーンアップする方法は?
コツはRAII(リソース取得は初期化)を使ってリソースを管理することです。
ポインター メンバーがある場合は、コンストラクターから例外がスローされると自動的にクリーンアップ ジョブを実行する生のポインターの代わりにスマート ポインターを使用します。
リソースが破棄されたときにリソースを解放するデータ メンバー (別名 RAII) を使用します。
例えば:
struct TwoStrings {
std::string string1;
std::string string2;
TwoStrings(const std::string &input) : string1(input) {
if (!input[1] == ':') {
throw std::logic_error('not a Windows absolute path');
// yes, absolute paths can begin \\, this is a toy example
}
if (input.back() == '\\') {
string2 = input;
} else {
string2 = input + "\\";
}
}
};
logic_error
コンストラクターが (またはのいずれか)をスローするbad_alloc
と、既に初期化されているデータ メンバーstring1
が破棄され、リソースが解放されます。さらに言えばstring2
も破棄されますが、コンストラクターがスローした場合string2
はまだ空でなければならないため、特に影響はありません。
string
はリソースを管理するクラスの例ですが、他にもたくさんあります。それらの中で最も柔軟なものは「スマート ポインター」と呼ばれ、文字の自己割り当て配列だけでなく、ほぼすべてのリソースを管理するように構成できますstring
。
例外がスローされると、スタックはキャッチ ポイントまで展開されます。その結果、その中で構築されていたすべてが破壊されます。
ポイントは、すべての賢明なリソースを、デストラクタが関連するリソースの破棄を処理するクラスにラップすることです。
リソースがヒープに割り当てられたオブジェクトである場合、スマート ポインターはまさにそれを行います (破棄時にポイントされたオブジェクトを削除します)。リソースが開いているファイルである場合、ストリームは破棄時にそれを閉じます。それ以外の場合は、カスタム ラッパーが必要です。
ただし、多くの「リソース」は、それ自体が void* であるハンドラーによって表されることに注意してください。これにより、割り当てられたリソースで初期化し、削除関数を指定することで、スマートポインターも使用できます。
テクニックがうまく機能するかどうかは、好みと機会の問題です。
最善の方法は次のとおりです。コンストラクタでリソースを割り当て、デストラクタで割り当てを解除します。
C++ のテンプレートは、オブジェクトの作成をアトミックにできるため、この目的に非常に役立ちます。