我很感兴趣这是否是由标准强制执行的,以及是否被某些编译器所违反。我的观察是:

  • Visual Studio 2015/2017(带有/ EHsc):throw()函数中的堆栈未解绕(未调用d-tor),但是异常退出了功能,并被try / catch捕获。没有调用std::terminate。
  • gcc(6.3.0),未取消throw()函数中的堆栈,但随后调用了std::terminate(try / catch无法解决异常)。但是使用7.0(当前HEAD)时,没有取消堆栈堆栈,因此立即调用std::termiante。
    实际上,gcc 7.0甚至对此发出警告:warning: throw will always call terminate() [-Wterminate]表示NoExceptFunctionWithObj2()。它使throw()的行为与noexcept(true)相同。
  • clang,在所有版本中,我都检查了展开函数堆栈(调用了对象d-tors),然后调用了std::terminate。

  • Test code:
    #include <iostream>
    #include <string>
    #include <vector>
    
    struct TestDataWithoutNoexcept {
      TestDataWithoutNoexcept() {
        std::cout << __FUNCTION__ << "\n";
      }
      ~TestDataWithoutNoexcept() {
        std::cout << __FUNCTION__ << "\n";
      }
      TestDataWithoutNoexcept(TestDataWithoutNoexcept const & rhs) {
        std::cout << __FUNCTION__ << "\n";
      }
      TestDataWithoutNoexcept(TestDataWithoutNoexcept && rhs) {
        std::cout << __FUNCTION__ << "\n";
      }
      TestDataWithoutNoexcept& operator=(TestDataWithoutNoexcept const& rhs) {
        std::cout << __FUNCTION__ << "\n";
      }
    };
    
    void NoExceptFunctionWithObj1() noexcept {
      TestDataWithoutNoexcept test;
      throw std::runtime_error("NoExceptFunctionWithObj1 ex.");
    }
    
    void NoExceptFunctionWithObj2() throw() {
      TestDataWithoutNoexcept test;
      throw std::runtime_error("NoExceptFunctionWithObj2 ex.");
    }
    
    int main()
    {
      // Now lets see whether stack is being unwound when exception is thrown in noexcept versus throw() function.
      std::cout << "\n See how dtors are called in noexcept or throw() functions\n";
      try {
        //NoExceptFunctionWithObj1();
      }
      catch (std::runtime_error& ex) {
        std::cout << ex.what();
      }
    
      try {
        NoExceptFunctionWithObj2();
      }
      catch (std::runtime_error& ex) {
        std::cout << "\nShouldn't this be shown? : " << ex.what();
      }
    }
    

    最佳答案

    是的,应该调用std::terminate。标准的latest published draft表示:

    15.4 [spec.except]第12段



    这意味着throw()严格等同于noexcept(true)throw()中不推荐使用C++17

    15.5.1 [except.terminate]



    不调用std::terminate表示MSVC不兼容。

    关于堆栈的处理,在您的示例中,编译器会进行所需的展开或不展开操作-这被指定为实现定义。

    历史上(在C++ 11之前)在这种情况下必须进行堆栈展开。然而,事实证明,这种强制行为的运行时成本太高,并且它阻碍了编译器进行某些优化(即使在非异常情况下)。结果,编译器现在可以自由地将其省略。

    经过@mike澄清后进行编辑。

    09-06 08:54