272 lines
13 KiB
Markdown
272 lines
13 KiB
Markdown
[except.spec]
|
||
|
||
# 14 Exception handling [[except]](./#except)
|
||
|
||
## 14.5 Exception specifications [except.spec]
|
||
|
||
[1](#1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L752)
|
||
|
||
The predicate indicating whether a function cannot exit via an exception
|
||
is called the [*exception specification*](#def:exception_specification "14.5 Exception specifications [except.spec]") of the function[.](#1.sentence-1)
|
||
|
||
If the predicate is false,
|
||
the function has a[*potentially-throwing exception specification*](#def:potentially-throwing,exception_specification "14.5 Exception specifications [except.spec]"),
|
||
otherwise it has a[*non-throwing exception specification*](#def:non-throwing_exception_specification "14.5 Exception specifications [except.spec]")[.](#1.sentence-2)
|
||
|
||
The exception specification is either defined implicitly,
|
||
or defined explicitly
|
||
by using a [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") as a suffix of a [function declarator](dcl.fct "9.3.4.6 Functions [dcl.fct]")[.](#1.sentence-3)
|
||
|
||
[noexcept-specifier:](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")
|
||
noexcept ( [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") )
|
||
noexcept
|
||
|
||
[2](#2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L774)
|
||
|
||
In a [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]"), the [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]"),
|
||
if supplied, shall be a contextually converted constant expression
|
||
of type bool ([[expr.const]](expr.const "7.7 Constant expressions"));
|
||
that constant expression is the exception specification of
|
||
the function type in which the [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") appears[.](#2.sentence-1)
|
||
|
||
A ( token that follows noexcept is part of the[*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") and does not commence an
|
||
initializer ([[dcl.init]](dcl.init "9.5 Initializers"))[.](#2.sentence-2)
|
||
|
||
The [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") noexcept without a [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") is
|
||
equivalent to the [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")noexcept(true)[.](#2.sentence-3)
|
||
|
||
[*Example [1](#example-1)*: void f() noexcept(sizeof(char[2])); // error: narrowing conversion of value 2 to type boolvoid g() noexcept(sizeof(char)); // OK, conversion of value 1 to type bool is non-narrowing â *end example*]
|
||
|
||
[3](#3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L796)
|
||
|
||
If a declaration of a function
|
||
does not have a [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]"),
|
||
the declaration has a potentially throwing exception specification
|
||
unless it is a destructor or a deallocation function
|
||
or is defaulted on its first declaration,
|
||
in which cases the exception specification
|
||
is as specified below
|
||
and no other declaration for that function
|
||
shall have a [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")[.](#3.sentence-1)
|
||
|
||
In an [explicit instantiation](temp.explicit "13.9.3 Explicit instantiation [temp.explicit]") a [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") may be specified,
|
||
but is not required[.](#3.sentence-2)
|
||
|
||
If a [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") is specified
|
||
in an explicit instantiation,
|
||
the exception specification shall be the same as
|
||
the exception specification of all other declarations of that function[.](#3.sentence-3)
|
||
|
||
A diagnostic is required only if the
|
||
exception specifications are not the same
|
||
within a single translation unit[.](#3.sentence-4)
|
||
|
||
[4](#4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L817)
|
||
|
||
If a virtual function has a
|
||
non-throwing exception specification,
|
||
all declarations, including the definition, of any function
|
||
that overrides that virtual function in any derived class
|
||
shall have a non-throwing
|
||
exception specification,
|
||
unless the overriding function is defined as deleted[.](#4.sentence-1)
|
||
|
||
[*Example [2](#example-2)*: struct B {virtual void f() noexcept; virtual void g(); virtual void h() noexcept = delete;};
|
||
|
||
struct D: B {void f(); // errorvoid g() noexcept; // OKvoid h() = delete; // OK};
|
||
|
||
The declaration ofD::f is ill-formed because it
|
||
has a potentially-throwing exception specification,
|
||
whereasB::f has a non-throwing exception specification[.](#4.sentence-2)
|
||
|
||
â *end example*]
|
||
|
||
[5](#5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L850)
|
||
|
||
An expression E is[*potentially-throwing*](#def:potentially-throwing,expression "14.5 Exception specifications [except.spec]") if
|
||
|
||
- [(5.1)](#5.1)
|
||
|
||
E is a [function call](expr.call "7.6.1.3 Function call [expr.call]") whose [*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1 General [expr.post.general]") has a function type,
|
||
or a pointer-to-function type,
|
||
with a potentially-throwing exception specification,
|
||
or
|
||
|
||
- [(5.2)](#5.2)
|
||
|
||
E implicitly invokes a function
|
||
(such as an overloaded operator,
|
||
an allocation function in a [*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]"),
|
||
a constructor for a function argument,
|
||
or a destructor)
|
||
that has a potentially-throwing exception specification,
|
||
or
|
||
|
||
- [(5.3)](#5.3)
|
||
|
||
E is a [*throw-expression*](expr.throw#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]") ([[expr.throw]](expr.throw "7.6.18 Throwing an exception")),
|
||
or
|
||
|
||
- [(5.4)](#5.4)
|
||
|
||
E is a dynamic_cast expression that casts to a reference type and
|
||
requires a runtime check ([[expr.dynamic.cast]](expr.dynamic.cast "7.6.1.7 Dynamic cast")),
|
||
or
|
||
|
||
- [(5.5)](#5.5)
|
||
|
||
E is a typeid expression applied to a
|
||
(possibly parenthesized) built-in unary * operator
|
||
applied to a pointer to a
|
||
polymorphic class type ([[expr.typeid]](expr.typeid "7.6.1.8 Type identification")),
|
||
or
|
||
|
||
- [(5.6)](#5.6)
|
||
|
||
any of the [immediate subexpressions](intro.execution#def:immediate_subexpression "6.10.1 Sequential execution [intro.execution]") of E is potentially-throwing[.](#5.sentence-1)
|
||
|
||
[6](#6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L887)
|
||
|
||
An implicitly-declared constructor for a class X,
|
||
or a constructor without a [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") that is defaulted on its first declaration,
|
||
has a potentially-throwing exception specification
|
||
if and only if
|
||
any of the following constructs is potentially-throwing:
|
||
|
||
- [(6.1)](#6.1)
|
||
|
||
the invocation of a constructor selected by overload resolution
|
||
in the implicit definition of the constructor
|
||
for class X to initialize a potentially constructed subobject, or
|
||
|
||
- [(6.2)](#6.2)
|
||
|
||
a subexpression of such an initialization,
|
||
such as a default argument expression, or,
|
||
|
||
- [(6.3)](#6.3)
|
||
|
||
for a default constructor, a default member initializer[.](#6.sentence-1)
|
||
|
||
[*Note [1](#note-1)*:
|
||
|
||
Even though destructors for fully-constructed subobjects
|
||
are invoked when an exception is thrown
|
||
during the execution of a constructor ([[except.ctor]](except.ctor "14.3 Stack unwinding")),
|
||
their exception specifications do not contribute
|
||
to the exception specification of the constructor,
|
||
because an exception thrown from such a destructor
|
||
would call the function std::terminate rather than escape the constructor ([[except.throw]](except.throw "14.2 Throwing an exception"), [[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#6.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[7](#7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L917)
|
||
|
||
The exception specification for an implicitly-declared destructor,
|
||
or a destructor without a [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]"),
|
||
is potentially-throwing if and only if
|
||
any of the destructors
|
||
for any of its potentially constructed subobjects
|
||
has a potentially-throwing exception specification or
|
||
the destructor is virtual and the destructor of any virtual base class
|
||
has a potentially-throwing exception specification[.](#7.sentence-1)
|
||
|
||
[8](#8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L927)
|
||
|
||
The exception specification for an implicitly-declared assignment operator,
|
||
or an assignment-operator without a [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") that is defaulted on its first declaration,
|
||
is potentially-throwing if and only if
|
||
the invocation of any assignment operator
|
||
in the implicit definition is potentially-throwing[.](#8.sentence-1)
|
||
|
||
[9](#9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L935)
|
||
|
||
A [deallocation function](basic.stc.dynamic.deallocation "6.8.6.5.3 Deallocation functions [basic.stc.dynamic.deallocation]") with no explicit [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") has a non-throwing exception specification[.](#9.sentence-1)
|
||
|
||
[10](#10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L940)
|
||
|
||
The exception specification for a comparison operator function ([[over.binary]](over.binary "12.4.3 Binary operators"))
|
||
without a [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") that is defaulted on its first declaration
|
||
is potentially-throwing if and only if
|
||
any expression
|
||
in the implicit definition is potentially-throwing[.](#10.sentence-1)
|
||
|
||
[11](#11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L948)
|
||
|
||
[*Example [3](#example-3)*: struct A { A(int = (A(5), 0)) noexcept;
|
||
A(const A&) noexcept;
|
||
A(A&&) noexcept; ~A();};struct B { B() noexcept;
|
||
B(const B&) = default; // implicit exception specification is noexcept(true) B(B&&, int = (throw 42, 0)) noexcept; ~B() noexcept(false);};int n = 7;struct D : public A, public B {int * p = new int[n]; // D::D() potentially-throwing, as the new operator may throw bad_alloc or bad_array_new_length// D::D(const D&) non-throwing// D::D(D&&) potentially-throwing, as the default argument for B's constructor may throw// D::~D() potentially-throwing};
|
||
|
||
Furthermore, ifA::~A() were virtual,
|
||
the program would be ill-formed since a function that overrides a virtual
|
||
function from a base class
|
||
shall not have a potentially-throwing exception specification
|
||
if the base class function has a non-throwing exception specification[.](#11.sentence-1)
|
||
|
||
â *end example*]
|
||
|
||
[12](#12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exceptions.tex#L981)
|
||
|
||
An exception specification is considered to be [*needed*](#def:needed,exception_specification "14.5 Exception specifications [except.spec]") when:
|
||
|
||
- [(12.1)](#12.1)
|
||
|
||
in an expression, the function is selected by
|
||
overload resolution ([[over.match]](over.match "12.2 Overload resolution"), [[over.over]](over.over "12.3 Address of an overload set"));
|
||
|
||
- [(12.2)](#12.2)
|
||
|
||
the function is odr-used ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule"));
|
||
|
||
- [(12.3)](#12.3)
|
||
|
||
the exception specification is compared to that of another
|
||
declaration (e.g., an explicit specialization or an overriding virtual
|
||
function);
|
||
|
||
- [(12.4)](#12.4)
|
||
|
||
the function is defined; or
|
||
|
||
- [(12.5)](#12.5)
|
||
|
||
the exception specification is needed for a defaulted
|
||
function that calls the function[.](#12.sentence-1)
|
||
[*Note [2](#note-2)*:
|
||
A defaulted declaration does not require the
|
||
exception specification of a base member function to be evaluated
|
||
until the implicit exception specification of the derived
|
||
function is needed, but an explicit [*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") needs
|
||
the implicit exception specification to compare against[.](#12.5.sentence-2)
|
||
â *end note*]
|
||
|
||
The exception specification of a defaulted
|
||
function is evaluated as described above only when needed; similarly, the[*noexcept-specifier*](#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") of a specialization
|
||
of a templated function
|
||
is instantiated only when needed[.](#12.sentence-2)
|