在析构函数中正确使用std :: uncaught_exception

8 c++ exception

有些文章总结"永远不会从析构函数中抛出异常",而"std :: uncaught_exception()没有用",例如:

但似乎我没有明白这一点.所以我写了一个小测试示例(见下文).

由于测试示例一切正常,我非常感谢有关它可能出错的一些评论?

测试结果:

./主要

    Foo::~Foo(): caught exception - but have pending exception - ignoring
    int main(int, char**): caught exception: from int Foo::bar(int)

./main 1

    Foo::~Foo(): caught exception -  but *no* exception is pending - rethrowing
    int main(int, char**): caught exception: from Foo::~Foo()

例:

// file main.cpp
// build with e.g. "make main"
// tested successfully on Ubuntu-Karmic with g++ v4.4.1
#include <iostream>

class Foo {
  public:

  int bar(int i) {
    if (0 == i)
      throw(std::string("from ") + __PRETTY_FUNCTION__);
    else
      return i+1;
  }

  ~Foo() {
    bool exc_pending=std::uncaught_exception();
    try {
      bar(0);
    } catch (const std::string &e) {
      // ensure that no new exception has been created in the meantime
      if (std::uncaught_exception()) exc_pending = true;

      if (exc_pending) {
        std::cerr << __PRETTY_FUNCTION__ 
                  << ": caught exception - but have pending exception - ignoring"
                  << std::endl;
      } else {
        std::cerr << __PRETTY_FUNCTION__
                  << ": caught exception -  but *no* exception is pending - rethrowing"
                  << std::endl;
        throw(std::string("from ") + __PRETTY_FUNCTION__);
      }
    }
  }

};

int main(int argc, char** argv) {
  try {
    Foo f;
    // will throw an exception in Foo::bar() if no arguments given. Otherwise
    // an exception from Foo::~Foo() is thrown.
    f.bar(argc-1);
  } catch (const std::string &e) {
    std::cerr << __PRETTY_FUNCTION__ << ": caught exception: " << e << std::endl;
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

补充:换句话说:尽管某些文章中有警告,但它按预期工作 - 那么它可能有什么问题呢?

R S*_*hko 8

Herb Sutter指的是另一个问题.他在谈论:

try
{
}
catch (...)
{
    try
    {
        // here, std::uncaught_exception() will return true
        // but it is still safe to throw an exception because
        // we have opened a new try block
    }
    catch (...)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

所以问题是如果std::uncaught_exception()返回true,你不确定是否可以安全地抛出异常.std::uncaught_exception()为了安全起见,返回true 时最终必须避免抛出异常.

  • 这实际上是不对的。此时您的异常已被捕获。您应该将try / catch放入析构函数中,该析构函数在堆栈展开时调用(由于活动异常)。在那种情况下,一个异常*正在*自动展开堆栈,但是您是正确的,然后在try / catch块中可以*抛出一个异常。 (2认同)

Den*_*ose 6

您的代码在技术上没有任何问题.这是非常安全的,因为你不会意外地终止,因为你在不安全的情况下抛出异常.问题是它也没有用,因为它有时也不会在安全的情况下抛出异常.你的析构函数的文档基本上必须说"这可能会或可能不会抛出异常".

如果它偶尔不会抛出异常,你也可能永远不会抛出异常.这样,你至少是一致的.