noexcept specifier
noexcept specifier (since C++11)
Specifies whether a function will throw exceptions or not.
Syntax
noexcept | (1) | |
---|---|---|
noexcept(expression) | (2) | |
throw() | (3) | (deprecated) |
1)
Same as noexcept
(
true
)
2) If expression evaluates to true
, the function is declared to not throw any exceptions.
3) Same as noexcept(true) | (since C++17) |
---|---|
3) Non-throwing dynamic exception specification (unlike noexcept(true) guarantees stack unwinding and may call std::unexpected) | (until C++17) |
expression | - | contextually converted constant expression of type bool |
---|
Explanation
The noexcept-specification is a part of the function type and may appear as part of any function declarator. | (since C++17) |
---|---|
The noexcept-specification is not a part of the function type (just like dynamic exception specification) and can only appear as a part of a lambda declarator or a top-level function declarator when declaring functions, variables, non-static data members of type function, pointer to function, reference to function, or pointer to member function, and also when declaring a parameter or a return type in one of those declarations that in turn happens to be a pointer or reference to function. It cannot appear in a typedef or type alias declaration. void f() noexcept; // the function f() does not throw void (*fp)() noexcept(false // fp points to a function that may throw void g(void pfa() noexcept // g takes a pointer to function that doesn't throw // typedef int (*pf)() noexcept; // error | (until C++17) |
Every function in C++ is either non-throwing
or potentially throwing
.
potentially-throwing
functions are:
functions declared with a dynamic exception specification. | (until C++17) |
---|
- functions declared with a dynamic exception specification.
(until C++17)
- functions declared with noexcept specifier whose expression evaluates to
false
Explicit instantiations may use the noexcept specifier, but it is not required. If used, the exception specification must be the same as for all other declarations. A diagnostic is required only if the exception specifications are not the same within a single translation unit.
Functions differing only in their exception specification cannot be overloaded (just like the return type, exception specification is part of function type, but not not part of the function signature) (since C++17).
void f() noexcept;
void f( // error: different exception specification
void g() noexcept(false
void g( // ok, both declarations for g are potentially-throwing
Pointers to non-throwing functions are implicitly convertible (since C++17)can be assigned to (until C++17) to pointers to potentially-throwing functions, but not the other way around.
void ft( // potentially-throwing
void (*fn)() noexcept = ft; // error
If a virtual function is non-throwing, all declarations, including the definition, of every overrider must be non-throwing as well, unless the overrider is defined as deleted:
struct B {
virtual void f() noexcept;
virtual void g(
virtual void h() noexcept = delete;
};
struct D: B {
void f( // ill-formed: D::f is potentially-throwing, B::f is non-throwing
void g() noexcept; // OK
void h() = delete; // OK
};
Non-throwing functions are permitted to call potentially-throwing functions. Whenever an exception is thrown and the search for a handler encounters the outermost block of a non-throwing function, the function std::terminate
is called:
extern void f( // potentially-throwing
void g() noexcept {
f( // valid, even if f throws
throw 42; // valid, effectively a call to std::terminate
}
The exception specification of a function template specialization is not instantiated along with the function declaration; it is instantiated only when needed (as defined below). The exception-specification of an implicitly-declared special member function is also evaluated only when needed (in particular, implicit declaration of a member function of a derived class does not require the exception-specification of a base member function to be instantiated). When the noexcept-specification of a function template specialization is needed, but hasn't yet been instantiated, the dependent names are looked up and any templates used in the expression are instantiated as if for the declaration of the specialization. A noexcept-specification of a function is considered to be needed in the following contexts. in an expression, where the function is selected by overload resolution the function is odr-used the function would be odr-used but appears in an unevaluated operand template | (since C++14) |
---|
- in an expression, where the function is selected by overload resolution
template<class T> T f() noexcept(sizeof(T) < 4 int main() { decltype(f<void>()) *p; // f unevaluated, but noexcept-spec is needed }
- the specification is needed to compare to another function declaration (e.g. on an virtual function overrider or on an explicit specialization of a function template)
(since C++14)
Formal definition of potentially-throwing expression
(used to determine the default exception specification of destructors, constructors, and assignment operators as described above):
See dynamic exception specification. | (until C++17) |
---|---|
An expression e is potentially-throwing if: e is a function call to a potentially-throwing function or pointer to function e makes an implicit call to a potentially-throwing function (such as an overloaded operator, an allocation function in a new-expression, a constructor for a function argument, or a destructor if e is a full-expression) e is a throw-expression e is a dynamic_cast that casts a polymorphic reference type e is a typeid expression applied to a dereferenced pointer to a polymorphic type e has an immediate subexpression that is potentially-throwing struct A { A(int = (A(5), 0)) noexcept; A(const A&) noexcept; A(A&&) noexcept; ~A( }; struct B { B() throw( B(const B&) = default; // implicit exception specification is noexcept(true) B(B&&, int = (throw Y(), 0)) noexcept; ~B() noexcept(false }; int n = 7; struct D : public A, public B { int * p = new intn; // D::D() potentially-throwing because of the new operator // D::D(const D&) non-throwing // D::D(D&&) potentially-throwing: the default argument for B’s constructor may throw // D:: D() potentially-throwing // note; if A::~A() were virtual, this program would be ill-formed because an overrider // of a non-throwing virtual cannot be potentially-throwing }; | (since C++17) |
e
is a function call to apotentially-throwing
function or pointe
r to function
struct A { A(int = (A(5), 0)) noexcept; A(const A&) noexcept; A(A&&) noexcept; ~A( }; struct B { B() throw( B(const B&) = default; // implicit exception specification is noexcept(true) B(B&&, int = (throw Y(), 0)) noexcept; ~B() noexcept(false }; int n = 7; struct D : public A, public B { int * p = new intn; // D::D() potentially-throwing because of the new operator // D::D(const D&) non-throwing // D::D(D&&) potentially-throwing: the default argument for B’s constructor may throw // D:: D() potentially-throwing // note; if A::~A() were virtual, this program would be ill-formed because an overrider // of a non-throwing virtual cannot be potentially-throwing };
(since C++17)
Notes
One of the uses of the constant expression is (along with the noexcept
operator) to define function templates that declare noexcept
for some types but not others.
Note that a noexcept
specification on a function is not a compile-time check; it is merely a method for a programmer to inform the compiler whether or not a function should throw exceptions. The compiler can use this information to enable certain optimizations on non-throwing functions as well as enable the noexcept
operator, which can check at compile time if a particular expression is declared to throw any exceptions. For example, containers such as std::vector
will move their elements if the elements' move constructor is noexcept
, and copy otherwise (unless the copy constructor is not accessible, but a potentially throwing move constructor is, in which case the strong exception guarantee is waived).
Deprecates
noexcept
is an improved version of throw()
, which is deprecated in C++11. Unlike pre-C++17 throw()
, noexcept
will not call std::unexpected
and may or may not unwind the stack, which potentially allows the compiler to implement noexcept
without the runtime overhead of throw()
. As of C++17, throw()
is redefined to be an exact equivalent of noexcept(true)
.
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 2039 | C++11 | only the expression before conversion is required to be constant | the conversion must also be valid in a constant expression |
Keywords
noexcept
.
Example
// whether foo is declared noexcept depends on if the expression
// T() will throw any exceptions
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
}
See also
noexcept operator | determines if an expression throws any exceptions (since C++11) |
---|---|
exception specification | specifies what exceptions are thrown by a function (deprecated) |
throw expression | signals an error and transfers control to error handler |
move_if_noexcept (C++11) | obtains an rvalue reference if the move constructor does not throw (function template) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.