noexcept
specifier (since C++11)
Specifies whether a function could throw exceptions.
Syntax
noexcept
|
(1) | ||||||||
noexcept( expression)
|
(2) | ||||||||
throw()
|
(3) | (deprecated in C++17) (removed in C++20) | |||||||
noexcept(true)
(
following noexcept
expression | - | contextually converted constant expression of type bool |
Explanation
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 typedef or type alias 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) |
The noexcept-specification is a part of the function type and may appear as part of any function declarator. |
(since C++17) |
Every function in C++ is either non-throwing or potentially throwing:
- potentially-throwing functions are:
|
(until C++17) |
-
- functions declared with
noexcept
specifier whose expression evaluates tofalse
- functions declared without
noexcept
specifier except for
-
- destructors unless the destructor of any potentially-constructed base or member is potentially-throwing (see below)
- default constructors, copy constructors, move constructors
-
- a constructor for a base or member that the implicit definition of the constructor would call is potentially-throwing (see below)
- a subexpression of such an initialization, such as a default argument expression, is potentially-throwing (see below)
- a default member initializer (for default constructor only) is potentially-throwing (see below)
- copy assignment operators, move assignment operators that are implicitly-declared or defaulted on their first declaration unless the invocation of any assignment operator in the implicit definition is potentially-throwing
- functions declared with
|
(since C++20) |
- non-throwing functions are all others (those with noexcept specifier whose expression evaluates to
true
as well as destructors, defaulted special member functions, and deallocation functions)
Functions differing only in their exception specification cannot be overloaded (just like the return type, exception specification is part of function type, but 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 (including pointers to member function) to non-throwing functions can be assigned to or used to initialize(until C++17) are implicitly convertible to (since C++17)
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
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
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<class T> T f() noexcept(sizeof(T) < 4); int main() { decltype(f<void>()) *p; // f unevaluated, but noexcept-spec is needed // error because instantiation of the noexcept specification // calculates sizeof(void) }
- the specification is needed to compare to another function declaration (e.g. on a virtual function overrider or on an explicit specialization of a function template)
- in a function definition
- the specification is needed because a defaulted special member function needs to check it in order to decide its own exception specification (this takes place only when the specification of the defaulted special member function is, itself, needed).
Formal definition of potentially-throwing expression (used to determine the default exception specification of destructors, constructors, and assignment operators as described above):
An expression e
is potentially-throwing if:
-
e
is a function call to a function, pointer to function, or pointer to member function which is potentially-throwing , unlesse
is a core constant expression (until C++17) -
e
makes an implicit call to a potentially-throwing function (such as an overloaded operator, an allocation function in anew
-expression, a constructor for a function argument, or a destructor ife
e
is athrow
-expressione
is adynamic_cast
that casts a polymorphic reference typee
is atypeid
expression applied to a dereferenced pointer to a polymorphic typee
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 int[n]; // 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 };
Notes
One of the uses of the constant expression is (along with the noexcept
operator) to define function templates that declare noexcept
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
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, may or may not unwind the stack, and will call std::terminate, 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)
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_noexcept_function_type |
201510L |
(C++17) | Make exception specifications be part of the type system |
Keywords
noexcept , throw (since C++17)(until C++20)
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 }
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 1330 | C++11 | an exception specification might be eagerly instantiated | it is only instantiated only if needed |
CWG 1740 | C++11 | a ( following noexcept | it can only be a part of noexcept specification |
CWG 2039 | C++11 | only the expression before conversion is required to be constant | the conversion must also be valid in a constant expression |
See also
noexcept operator(C++11)
|
determines if an expression throws any exceptions |
Dynamic exception specification(until C++17) | specifies what exceptions are thrown by a function (deprecated in C++11) |
throw expression
|
signals an error and transfers control to error handler |
(C++11)
|
converts the argument to an xvalue if the move constructor does not throw (function template) |