什么是noexcept有用?

时间:2014-12-07 19:16:06

标签: c++ visual-studio exception c++11 noexcept

我看到 C ++ 11 添加了noexcept关键字。但我真的不明白为什么它有用。

如果函数在不应该抛出时抛出 - 为什么我要让程序崩溃?

那我什么时候应该使用它?

此外,如何使用/ Eha并使用_set_se_translator进行编译?这意味着任何代码行都会抛出c ++异常 - 因为它可能抛出一个SEH异常(因为访问受保护的内存)并且它将被转换为c ++异常。

那会发生什么?

2 个答案:

答案 0 :(得分:37)

noexcept的主要用途是用于通用算法,例如,在调整std::vector<T>的大小时:对于有效的算法移动元素,必须事先知道没有任何移动会抛出。如果移动元素可能会抛出,则需要复制元素。使用noexcept(expr)运算符,库实现可以确定特定操作是否可以抛出。不投掷操作的属性成为合同的一部分:如果违反合同,所有投注都将被取消,并且可能无法恢复有效状态。在造成更多伤害之前拯救是自然的选择。

要传播有关noexcept操作的知识,不要抛出它也需要声明函数。为此,您必须使用noexceptthrow()noexcept(expr)使用常量表达式。在实现通用数据结构时,使用表达式的表单是必需的:使用表达式可以确定任何类型相关操作是否可能引发异常。

例如,std::swap()声明如下:

template <typename T>
void swap(T& o1, T& o2) noexcept(noexcept(T(std::move(o1)) &&
                        noexcept(o1 = std::move(o2)));

基于noexcept(swap(a, b)),库可以选择不同效率的某些操作实现:如果它只能swap()而不会有异常风险,它可能会暂时违反不变量并在以后恢复它们。如果可能抛出异常,则库可能需要复制对象而不是移动它们。

标准C ++库实现不太可能依赖于许多操作noexcept(true)。可能会检查的操作主要是那些涉及移动物体的操作,即:

  1. 类的析构函数(注意,析构函数默认为noexcept(true),即使没有任何声明;如果你有可能抛出的析构函数,你需要声明它,例如: T::~T() noexcept(false))。
  2. 移动运算符,即移动构造(T::T(T&&))并移动分配(T::operator=(T&&))。
  3. 类型swap()操作(swap(T&, T&),可能还有成员版T::swap(T&))。
  4. 如果这些操作中的任何一个偏离默认值,您应该相应地声明它以获得最有效的实现。这些操作的生成版本声明它们是否根据用于成员和基础的相应操作抛出异常。

    虽然我可以想象将来或某些特定的库可能会添加一些操作,但我现在可能不会将操作声明为noexcept。如果出现其他功能,使其变为noexcept,则可以在将来声明(并且可能根据需要进行更改)。

答案 1 :(得分:4)

程序可能崩溃的原因是因为noexcept告诉优化器你的代码不会抛出。如果确实如此 - 那么,无法预测优化代码会发生什么。

对于MSVC ++,您必须检查实施noexcept时会发生什么。从标准的角度来看,SEH是未定义的行为。访问受保护的内存现在已经崩溃了。