関数 foo(MyClass* mc) が mc のコピーを内部データ構造に保持し、使用されなくなったときにオブジェクトが削除されることを保証する場合を考えてみましょう。
void foo(MyClass* mc) // acquires ownership of mc; may throw
{
// code that may throw
bar(mc); // acquires mc; may also throw
}
この関数がスローする可能性のあるコード (たとえば、OutOfMemory 例外) を実行すると、問題が発生します。ポインターがデータ構造に保存される前に例外が発生した場合、呼び出し元はそれに対して責任を負わないため、関数がアンワインドする前にオブジェクトを明らかに解放する必要があります (呼び出し元は、ポインターが実際にオブジェクトに保存されたかどうかさえ知りません)。データ構造かどうか)。
スコープ ガードを使用してこれを処理するために RAII を使用することもできますが、これは非常に扱いにくく、オーバーヘッドが発生します (ポインターを取得するすべての関数で実行する必要があります)。
動的に割り当てられたオブジェクトが取得されるたびにこれを行う必要がありますか、それともより適切な方法がありますか?!
template <class T>
struct VerifyAcq {
T* ptr;
bool done;
VerifyAcq(T* ptr):ptr(ptr) { done = false; }
~VerifyAcq() {
if (!done) delete ptr;
}
};
void foo(MyClass* mc) // acquires mc; may throw
{
VerifyAcq<MyClass> va(mc);
// code that may throw
bar(mc); // acquires mc; may throw; must implement the same mechanism!
va.done = true;
}
// Note: there might be no public way of "undoing" what bar has done (no rollbak)
// and even if there was, what if it could also throw?...
ポインターを削除するために呼び出し元が例外をキャッチすることはできません。これは、例外をスローする前に、関数がポインターをデータ構造に正常に追加した可能性があり、オブジェクトを解放するとデータ構造が不安定になる (ダングリング ポインター) ためです。