什么没有除了有用

What is noexcept useful for?

本文关键字:有用 什么      更新时间:2023-10-16

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

如果函数在不应该抛出的时候抛出 - 为什么我希望程序崩溃?

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

另外,它将如何与使用/Eha 编译和使用 _set_se_translator 一起工作?这意味着任何代码行都可以抛出 c++ 异常 - 因为它可能会抛出 SEH 异常(因为访问受保护的内存(,它将被转换为 c++ 异常。

那会发生什么呢?

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&)(。

如果这些操作中的任何一个偏离默认值,则应相应地声明它以获得最有效的实现。这些操作的生成版本声明它们是否根据用于成员和基的相应操作引发异常。

尽管我可以想象将来可能会添加某些操作或由某些特定库添加某些操作,但我可能不会暂时将操作声明为noexcept。如果出现其他功能,noexcept可以声明它们(并可能根据需要进行更改(。

程序可能崩溃的原因是noexcept告诉优化器您的代码不会抛出。如果是这样 - 好吧,没有办法预测优化代码会发生什么。

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