我有一个简单的C ++对象,我在函数F()的开头创建,以确保在F()的开始和返回时调用两个匹配的函数(OpDo,OpUndo),方法是使用对象的构造函数和析构函数。但是,如果在F()的主体内抛出异常,我不希望撤消操作。这可以干净利落吗?我已经阅读了 std :: uncaught-exception ,但似乎并未建议使用它。
答案 0 :(得分:6)
大多数人使用std::uncaught_exception()
来尝试判断异常是否未决,因此如果没有异常,它们可以从析构函数中抛出异常。这通常被认为不是一个好主意。
如果你想在没有抛出异常的情况下撤消操作,它应该可以解决问题。
请记住,析构函数是释放对象所拥有的任何资源的最后机会,因为在析构函数结束后,对象不存在,并且它所拥有的任何资源现在都会永久泄露。如果OpDo()
分配任何内存或文件句柄或其他任何内容,则无论如何都需要在析构函数中处理它。
答案 1 :(得分:0)
我们假设您的F返回一些类助手:
Helper F()
{
MyClass doUndoWrapper;
}
当流量正常时 - 创建帮助程序。引发异常时,不会创建Helper的副本。尝试通过放置到Helper的私有区域构造函数并将F声明为朋友来使用此语义 - 因此没有人可以创建帮助器。
class Helper
{
private:
friend Helper F();
Helper(){ //place there OpDo semantic - first entry
// construct this class
Helper(const Helper& copy){ //this must present to allow stack operations
// copy constructor will be called at end of `F` to return value
// so place OpUndo semantic there to mark success without exception
答案 2 :(得分:0)
您可以颠覆Scope Guard idiom。如果没有抛出异常,我们不会在析构函数中执行不操作,而是在没有抛出异常的情况下将其反转并且仅执行某些操作:
class DoUndoRAII{
public:
DoUndoRAII()
: noexcept_(false)
{
// your stuff here
}
~DoUndoRAII(){
if(noexcept_){
// do whatever you need to do
}
}
void no_exception(){
noexcept_ = true;
}
private:
bool noexcept_;
};
void func(){
DoUndoRAII do_undo;
// last line
do_undo.no_exception();
}
抛出异常时,永远不会调用do_undo.no_exception()
,因此永远不会将noexcept_
值设置为true。 :)可以找到一个例子here on Ideone。