7

我有一个简单的 C++ 对象,我在函数 F() 的开头创建它,以确保在 F() 的开头和返回时调用两个匹配的函数(OpDo、OpUndo),方法是使用对象的构造函数和析构函数。但是,我不希望在 F() 的主体内引发异常的情况下撤消该操作。这可以干净地做吗?我已阅读有关std::uncaught-exception 的信息,但似乎不推荐使用它。

4

3 回答 3

6

大多数人过去常常std::uncaught_exception()尝试判断异常是否处于未决状态,因此如果还没有异常,他们可以从析构函数中抛出异常。这通常被认为不是一个好主意。

如果您不想在抛出异常的情况下撤消操作,那么它应该可以解决问题。

请记住,析构函数是您释放对象拥有的任何资源的最后机会,因为在析构函数结束后,该对象不存在,并且它持有的任何资源现在都永久泄漏。如果OpDo()分配任何内存或文件句柄或其他任何内容,无论如何您都需要在析构函数中处理它。

于 2010-10-25T20:31:37.567 回答
1

你可以颠覆Scope Guard 的成语当没有抛出异常时,我们不会在析构函数中做某事,而是将其反转并且在没有抛出异常时才做某事:

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。:) 可以在 Ideone 上找到一个示例。

于 2011-04-17T08:08:49.510 回答
0

让我们假设您的 F 返回一些类 Helper:

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
于 2010-10-25T20:40:23.047 回答