如何在 C++ 中使用 noexcept 或者它是如何工作的?

How to use noexcept in C++ or How does it work?

我无法理解 C++11/14 中 noexcept 关键字的用途和目的。我知道这是一个不发出 exceptions 的函数的签名。但是真的有用吗?

看看下面这段代码:

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
void seev (vector<int> &v) noexcept;
void seev (vector<int> &v) noexcept
{
    for (int i=0;i<10;++i)
    {
        cout<<v.at(i)<<' ';
    }
}
int main()
{
    vector<int> v {1,2,3,4,5};
    seev(v);
    return 0;
}

上面的代码肯定会抛出一个out_of_range exception。所以这里使用noexcept是没有用的,还是?

我的查询是:

  1. noexcept 是如何工作的?

  2. 如何使用?

  3. 什么 throw() 做不到而 noexcept 可以做到?

noexcept 表示函数不打算抛出异常,这是您作为开发人员提供的保证,编译器不会强制执行。因此,在您的函数调用可能会抛出您自己没有发现的异常的情况下使用它是不好的。

删除了整个范围的 throw() 说明符,因为异常说明符在 C++ 中不是最佳的,请参阅:Difference between C++03 throw() specifier C++11 noexcept

noexcept 的优点是不说明抛出的是哪个异常,而是说明是否抛出异常。它接受一个参数,如果您希望该函数抛出异常,该参数可能是 false

这个的用途,例如可以在一个继承的 class 结构中,其中一个超级 class 希望 "enforce" 到一个继承的 class,一个特定的虚函数不允许抛出异常。此外,编译器可能会使用这些信息进行优化。

noexcept 也是一个可以计算表达式的运算符,并且 return 该表达式是否会抛出异常,根据 § 5.3.7.

5.3.7 noexcept operator [expr.unary.noexcept]

1 The noexcept operator determines whether the evaluation of its operand, which is an unevaluated operand (Clause 5), can throw an exception (15.1). noexcept-expression: noexcept ( expression )

2 The result of the noexcept operator is a constant of type bool and is an rvalue.

3 The result of the noexcept operator is false if in a potentially-evaluated context the expression would contain

— a potentially-evaluated call to a function, member function, function pointer, or member function pointer that does not have a non-throwing exception-specification (15.4), unless the call is a constant expression (5.19),
— a potentially-evaluated throw-expression (15.1),
— a potentially-evaluated dynamic_cast expression dynamic_cast(v), where T is a reference type, that requires a run-time check (5.2.7), or
— a potentially-evaluated typeid expression (5.2.8) applied to a glvalue expression whose type is a polymorphic class type (10.3).
Otherwise, the result is true.

我无法像 Scott Meyers 那样解释可能的优化:http://aristeia.com/EC++11-14/noexcept%202014-03-31.pdf from his blog post: Declare functions noexcept whenever possible?

The difference between unwinding the call stack and possibly unwinding it has a surprisingly large impact on code generation. In a noexcept function, optimizers need not keep the runtime stack in an unwindable state if an exception would propagate out of the function, nor must they ensure that objects in a noexcept function are destroyed in the inverse order of construction should an exception leave the function. The result is more opportunities for optimization, not only within the body of a noexcept function, but also at sites where the function is called. Such flexibility is present only for noexcept functions. Functions with “throw()” exception specifications lack it, as do functions with no exception specification at all.

函数的 noexcept 规范只是程序员通知编译器函数是否应该抛出异常的一种方法。

编译器可以使用此信息对非抛出函数启用某些优化以及启用 noexcept 运算符,它可以在编译时检查特定表达式是否声明为抛出任何异常。

例如,如果元素的移动构造函数是 noexcept,容器如 std::vector 将移动它们的元素,否则复制(除非复制构造函数不可访问,但可能会抛出移动构造函数,在在这种情况下,强例外保证被放弃)。

noexcept 是 throw() 的改进版本,在 C++11 中已弃用。与 throw() 不同,noexcept 不会调用 std::unexpected,并且可能会也可能不会展开堆栈,这可能允许编译器在没有 throw().

的运行时开销的情况下实现 noexcept

更多详情,请访问以下网站

编辑:示例源代码以说明以上几点。

// whether foo is declared noexcept depends on if the expression
// T() will throw any exceptions, check in compile time
template <class T>
void foo() noexcept(noexcept(T())) {     
}

void bar() noexcept(true) {    
}

void baz() noexcept {
    throw 42;     
}  // noexcept is the same as noexcept(true)

int main() 
{
    foo<int>();  // noexcept(noexcept(int())) => noexcept(true), so this is fine

    bar();  // fine
    baz();  // compiles, but at runtime this calls std::terminate
}

我发布了 2 段代码来解释您的问题:

代码 1:

#include <iostream>
using namespace std;
void foo() noexcept     // see the noexcept specifier
{
    throw 42;
}
int main()
{
    try
    {
        foo();
    }
    catch(...)
    {
        cerr<<"exception caught\n";
    }
    return 0;
}

这里的输出是:-

terminate called after throwing an instance of 'int'

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

如果我删除 noexcept 则:

代码 2:

#include <iostream>
using namespace std;
void foo()    // noexcept is eliminated
{
    throw 42;
}
int main()
{
    try
    {
        foo();
    }
    catch(...)
    {
        cerr<<"exception caught\n";
    }
    return 0;
}

输出将是:-

exception caught

因为 foo 被签名为 noexcept,因此 terminate 被调用。

默认情况下,继承构造函数和隐式声明的默认构造函数、复制构造函数、移动构造函数、析构函数、复制赋值运算符和移动赋值运算符都是 noexcept(true),除非它们需要调用函数是 noexcept(false),在这种情况下,这些函数是 noexcept(false).

你也可以这样写:

cout << boolalpha << noexcept(foo);   // here noexcept acts as 
                                     // an operator instead of a specifier

上面的行将检查 foo 是否会抛出 exception。如果它会抛出,那么 return 值将是 true 否则 false.

您可以在此处阅读更多相关信息:http://scottmeyers.blogspot.dk/2014/03/declare-functions-noexcept-whenever.html