考虑函数 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?...
调用者不能为了删除指针而捕获异常,因为在抛出异常之前,函数可能已经成功地将指针添加到数据结构中,释放对象会使数据结构变得不健全(悬空指针)。