3

最近我试图回答一个我认为是关于异常规范的简单问题。noexcept最终的结果是我发现我的基本理解noexcept是错误的。

在阅读当前的标准草案以纠正我的误解时,我发现自己问了一些关于这里noexcept没有回答的问题。

  1. 应该noexcept被认为是一种安全保证,即调用时的函数不仅不会抛出而且不会破坏状态吗?
  2. 假设 (1.) 是错误的:使用noexcept可移植的FailFast来终止应用程序而不进行清理以防止损坏保存状态是否正确?

对(2.)的澄清:目的只是为了防止析构函数从堆栈进一步向上调用,而noexcept不是防止在其中展开。这是基于这样的假设,即这是一个完美的 RAII 环境,并且堆栈上的析构函数可以将全局状态刷新到持久性,从而破坏它。

不执行展开的示例:

#include <iostream>
#include <exception>

namespace{
   struct foo{
       void change_state() noexcept
       {
          // change state and fail
          throw std::exception();
       }
       ~foo(){
          std::cout << "Destructor called, saved state corrupted!" <<std::endl;
       }
    };
}


int main(){
    ::std::set_terminate([](){
        std::cout<< "Terminate called" <<std::endl;
    });

    foo f;
    f.change_state();
    return 0;
}

的工作示例noexcept

4

2 回答 2

2
  1. 是的。一个函数不应该破坏状态、周期,不管它是否抛出。它可能想要抛出异常的事实并不重要。[当然,不能保证它不会使程序崩溃。不过,这种行为可能应该被记录下来。;-)]
  2. 亩。如果函数希望通过noexcept;抛出,它不应该打扰抛出。它应该只调用std::terminate(或std::abort)。
于 2014-02-17T15:26:39.080 回答
1

noexcept是合同保证,很像assert 不能关闭的。如果标记的函数noexcept 试图通过异常退出,则违反了后置条件,您不能指望任何东西;该程序将被终止。因此,1 为假。

至于2,就更难了。实现可能会展开堆栈,直到它尝试使用noexcept;离开函数。不是 100% 清楚(至少对我而言)它可能不会进一步展开堆栈。如果我想在不进行清理的情况下终止应用程序,那么我将调用abort(),它保证立即退出而无需任何进一步的操作。它还准确地告诉读者正在发生的事情,而不是指望不同功能的某些次要效果。

于 2014-02-17T16:30:29.383 回答