我最近的任务是在代码的一部分中查找内存泄漏.泄漏最终出现在特定对象的析构函数中……我发现了一些非常奇怪的东西.一位前同事写道:
File::~File() try { Clear(); } catch (...) { Log("caught exception"); }
文件类继承自一些基类.我的第一个问题是:这是严格合法的C吗?它在Visual Studio 2008中编译,但我向几个朋友/同事展示了它们,并且它们相当惊恐,它的工作原理.
但它实际上并没有按预期工作:这个对象继承的基类有一个现在永远不会被调用的析构函数(而不是如果你只是将析构函数包装在常规方法块中,将try / catch作为一部分)那个方法).
解决方法
这是一个功能尝试块,它是完全合法的.
例如,参见here.
你可以在一个函数中执行某些操作的唯一一次你在一个函数中的普通try块中无法做的事情就是捕获构造函数初始化列表中表达式抛出的异常(甚至你最终还是要抛出一些东西),但这不适用于此.
这个GOTW #66特别有趣,尽管它更多地集中在构造函数上.它包含这个“道德”:
Since destructors should never emit an exception,destructor function-try-blocks have no practical use at all.
只是为了补充说明,编写的代码将导致由于ISO / IEC 14882:2003 15.3 [except.handle] / 16而被捕获的任何异常:
The exception being handled is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor. […]
但是,在函数try块的处理程序中为析构函数提供无参数返回是合法的 – 它只在构造函数的函数try块中被禁止 – 这将抑制异常的重新抛出.因此,这些替代方案中的任何一个都可以防止异常离开析构函数.
File::~File() try { Clear(); } catch (...) { Log("caught exception"); return; }
File::~File() { try { Clear(); } catch (...) { Log("caught exception"); } }