2014-02-17 45 views
3

最近,我试图回答什么,我认为将是对noexcept例外规范simple question。最终的结果是,我发现我对noexcept的基本理解是错误的。noexcept和可靠性保证

在阅读the current draft standard以纠正我的误解时,我发现自己问了一些关于noexcept的问题,这些问题未回答here

  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; 
} 

Working example of noexcept

+0

我的理解'noexcept':即使这件事情引发我不想知道。所以它对于“安全”或“正确性”并不真正起作用,它通过防止抛出异常而起作用,因此你的程序不会因此而终止。 – user2485710

+1

如果一个异常到达标记为“noexcept”的函数的最外层,则调用std :: terminate。它根本不抑制异常。它提供了一个屏障,在这个屏障上不会抛出异常 – Mgetz

+0

我之前写的是关于_runtime_,'noexcept'在编译时工作,所以它是编译器的一个提示,编译器评估你的程序,如果有可能抛出异常,您有机会在_runtime_之前更正此错误,因为'noexcept'运算符将在_compile time_时失败。它在某些方面类似于'type traits',你定义一个属性需要被评估为'true',如果不是编译器警告你的话,如果测试通过你知道在_runtime_你将有你的类型定义在你的'特质'条件。 'noexcept'同样的事情。 – user2485710

回答

2
  1. 是。函数不应该损坏状态,期限,不管它是否抛出。事实上,它可能有想要抛出异常是不重要的。 [当然,不能保证它不会使程序崩溃。不过,这种行为应该可以记录下来。 ;-)]
  2. Mu。一个函数不应该打扰投掷,如果它期望通过noexcept;它应该调用std::terminate(或std::abort)。
+0

我明白你在这样的失败应该是明确的,而不是依赖'noexcept'的行为。我想,当标记为“noexcept”的函数调用一个抛出的函数时,我在理论上捅了捅。你是否捕获异常,然后调用'std :: terminate'? – Mgetz

+1

呃......如果外部函数捕捉并处理异常是有用的,那么它当然应该这样做。之后,它可能应该调用'terminate'来证明它不会维护类不变量。 “扔”的意思是“但不用担心,我们没事”。据说,如果'throw'离开'noexcept'只有一英寸的屏幕空间,那并不重要。 – Sneftel

1

noexcept是合同保证,非常类似于不能关闭的assert 。如果一个函数通过异常标记noexcept 试图退出,一个后置条件已经 侵犯,你不能指望任何东西;程序将终止 。因此,1是错误的。

至于2,是比较困难的。执行可能将 展开,直到它试图离开函数 noexcept;它不是100%清楚(至少对我来说)它可能不会进一步展开堆栈。如果我要终止,而无需清理 应用程序,然后我会打电话给abort(),这是 保证立即退出而不进行任何进一步的行动。它 也告诉读者到底发生了什么,而不是 指望一个不同的功能的一些次要影响。

+0

所以你会用'catch'来包装这个特殊情况下的任何不安全(非'noexcept')调用?然后调用'std :: abort'来防止进一步展开? (我假设'noexcept'函数中的展开不会损坏保存的状态) – Mgetz

+0

@Mgetz通常,我不会进行任何不安全的调用:-)。否则,如果我想吞下它们(通常是析构函数的情况下,例如,可能会在堆栈展开期间调用它),我只会将它们包裹起来。 –

+0

看来我的问题似乎并不清楚......意图只是为了防止析构函数调用比noexcept更靠近堆栈。但是如果我理解你......你所说的是,在全局保存状态可能被破坏的情况下,最好像在noexcept环境中一样行动,然后在需要时立即“中止”。 – Mgetz