- tmp/tmpklh98kwr/{from.md → to.md} +212 -188
tmp/tmpklh98kwr/{from.md → to.md}
RENAMED
|
@@ -1,7 +1,9 @@
|
|
| 1 |
# Exception handling <a id="except">[[except]]</a>
|
| 2 |
|
|
|
|
|
|
|
| 3 |
Exception handling provides a way of transferring control and
|
| 4 |
information from a point in the execution of a thread to an exception
|
| 5 |
handler associated with a point previously passed by the execution. A
|
| 6 |
handler will be invoked only by throwing an exception in code executed
|
| 7 |
in the handler’s try block or in functions called from the handler’s try
|
|
@@ -22,24 +24,24 @@ handler-seq:
|
|
| 22 |
handler handler-seqₒₚₜ
|
| 23 |
```
|
| 24 |
|
| 25 |
``` bnf
|
| 26 |
handler:
|
| 27 |
-
'catch (' exception-declaration ')' compound-statement
|
| 28 |
```
|
| 29 |
|
| 30 |
``` bnf
|
| 31 |
exception-declaration:
|
| 32 |
attribute-specifier-seqₒₚₜ type-specifier-seq declarator
|
| 33 |
attribute-specifier-seqₒₚₜ type-specifier-seq abstract-declaratorₒₚₜ
|
| 34 |
'...'
|
| 35 |
```
|
| 36 |
|
| 37 |
The optional *attribute-specifier-seq* in an *exception-declaration*
|
| 38 |
-
appertains to the parameter of the catch clause
|
| 39 |
|
| 40 |
-
A *try-block* is a *statement*
|
| 41 |
|
| 42 |
[*Note 1*: Within this Clause “try block” is taken to mean both
|
| 43 |
*try-block* and *function-try-block*. — *end note*]
|
| 44 |
|
| 45 |
A `goto` or `switch` statement shall not be used to transfer control
|
|
@@ -47,19 +49,19 @@ into a try block or into a handler.
|
|
| 47 |
|
| 48 |
[*Example 1*:
|
| 49 |
|
| 50 |
``` cpp
|
| 51 |
void f() {
|
| 52 |
-
goto l1; //
|
| 53 |
-
goto l2; //
|
| 54 |
try {
|
| 55 |
goto l1; // OK
|
| 56 |
-
goto l2; //
|
| 57 |
l1: ;
|
| 58 |
} catch (...) {
|
| 59 |
l2: ;
|
| 60 |
-
goto l1; //
|
| 61 |
goto l2; // OK
|
| 62 |
}
|
| 63 |
}
|
| 64 |
```
|
| 65 |
|
|
@@ -118,23 +120,22 @@ try : i(f(ii)), d(id) {
|
|
| 118 |
}
|
| 119 |
```
|
| 120 |
|
| 121 |
— *end example*]
|
| 122 |
|
| 123 |
-
In this
|
| 124 |
-
relation
|
| 125 |
|
| 126 |
## Throwing an exception <a id="except.throw">[[except.throw]]</a>
|
| 127 |
|
| 128 |
Throwing an exception transfers control to a handler.
|
| 129 |
|
| 130 |
[*Note 1*: An exception can be thrown from one of the following
|
| 131 |
-
contexts: *throw-expression*s
|
| 132 |
-
[[basic.stc.dynamic.allocation]]
|
| 133 |
-
|
| 134 |
-
[[
|
| 135 |
-
[[structure.specifications]]). — *end note*]
|
| 136 |
|
| 137 |
An object is passed and the type of that object determines which
|
| 138 |
handlers can catch it.
|
| 139 |
|
| 140 |
[*Example 1*:
|
|
@@ -177,39 +178,39 @@ try {
|
|
| 177 |
```
|
| 178 |
|
| 179 |
— *end example*]
|
| 180 |
|
| 181 |
When an exception is thrown, control is transferred to the nearest
|
| 182 |
-
handler with a matching type
|
| 183 |
handler for which the *compound-statement* or *ctor-initializer*
|
| 184 |
following the `try` keyword was most recently entered by the thread of
|
| 185 |
control and not yet exited.
|
| 186 |
|
| 187 |
-
Throwing an exception copy-initializes ([[dcl.init]],
|
| 188 |
-
temporary object, called the *exception object*.
|
| 189 |
-
temporary is used to initialize the variable
|
| 190 |
-
*handler*
|
| 191 |
-
would be an incomplete type
|
| 192 |
-
|
|
|
|
| 193 |
|
| 194 |
The memory for the exception object is allocated in an unspecified way,
|
| 195 |
except as noted in [[basic.stc.dynamic.allocation]]. If a handler exits
|
| 196 |
by rethrowing, control is passed to another handler for the same
|
| 197 |
exception object. The points of potential destruction for the exception
|
| 198 |
object are:
|
| 199 |
|
| 200 |
- when an active handler for the exception exits by any means other than
|
| 201 |
rethrowing, immediately after the destruction of the object (if any)
|
| 202 |
declared in the *exception-declaration* in the handler;
|
| 203 |
-
- when an object of type `std::exception_ptr`
|
| 204 |
refers to the exception object is destroyed, before the destructor of
|
| 205 |
`std::exception_ptr` returns.
|
| 206 |
|
| 207 |
Among all points of potential destruction for the exception object,
|
| 208 |
there is an unspecified last one where the exception object is
|
| 209 |
-
destroyed. All other points happen before that last one
|
| 210 |
-
[[intro.races]]).
|
| 211 |
|
| 212 |
[*Note 2*: No other thread synchronization is implied in exception
|
| 213 |
handling. — *end note*]
|
| 214 |
|
| 215 |
The implementation may then deallocate the memory for the exception
|
|
@@ -220,61 +221,65 @@ unless caught, stored, and rethrown using appropriate library functions;
|
|
| 220 |
see [[propagation]] and [[futures]]. — *end note*]
|
| 221 |
|
| 222 |
When the thrown object is a class object, the constructor selected for
|
| 223 |
the copy-initialization as well as the constructor selected for a
|
| 224 |
copy-initialization considering the thrown object as an lvalue shall be
|
| 225 |
-
non-deleted and accessible, even if the copy/move operation is elided
|
| 226 |
-
[[class.copy]]
|
| 227 |
-
[[class.dtor]]
|
| 228 |
|
| 229 |
An exception is considered caught when a handler for that exception
|
| 230 |
-
becomes active
|
| 231 |
|
| 232 |
[*Note 4*: An exception can have active handlers and still be
|
| 233 |
considered uncaught if it is rethrown. — *end note*]
|
| 234 |
|
| 235 |
-
If the exception handling mechanism handling an uncaught exception
|
| 236 |
-
[[except.uncaught]]
|
| 237 |
-
exception, `std::terminate` is called
|
| 238 |
|
| 239 |
[*Example 2*:
|
| 240 |
|
| 241 |
``` cpp
|
| 242 |
struct C {
|
| 243 |
C() { }
|
| 244 |
C(const C&) {
|
| 245 |
if (std::uncaught_exceptions()) {
|
| 246 |
-
throw 0; // throw during copy to handler's exception-declaration object
|
| 247 |
}
|
| 248 |
}
|
| 249 |
};
|
| 250 |
|
| 251 |
int main() {
|
| 252 |
try {
|
| 253 |
-
throw C(); // calls std::terminate
|
| 254 |
-
// exception-declaration object is not elided
|
| 255 |
} catch(C) { }
|
| 256 |
}
|
| 257 |
```
|
| 258 |
|
| 259 |
— *end example*]
|
| 260 |
|
| 261 |
-
[*Note 5*:
|
| 262 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 263 |
|
| 264 |
## Constructors and destructors <a id="except.ctor">[[except.ctor]]</a>
|
| 265 |
|
| 266 |
As control passes from the point where an exception is thrown to a
|
| 267 |
-
handler,
|
| 268 |
-
|
| 269 |
|
| 270 |
-
|
| 271 |
constructed, but not yet destroyed, since the try block was entered. If
|
| 272 |
an exception is thrown during the destruction of temporaries or local
|
| 273 |
-
variables for a `return` statement
|
| 274 |
-
|
| 275 |
-
|
| 276 |
|
| 277 |
[*Example 1*:
|
| 278 |
|
| 279 |
``` cpp
|
| 280 |
struct A { };
|
|
@@ -292,37 +297,44 @@ A f() {
|
|
| 292 |
return {}; // #2
|
| 293 |
}
|
| 294 |
```
|
| 295 |
|
| 296 |
At \#1, the returned object of type `A` is constructed. Then, the local
|
| 297 |
-
variable `b` is destroyed
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
|
| 302 |
— *end example*]
|
| 303 |
|
| 304 |
If the initialization or destruction of an object other than by
|
| 305 |
delegating constructor is terminated by an exception, the destructor is
|
| 306 |
invoked for each of the object’s direct subobjects and, for a complete
|
| 307 |
object, virtual base class subobjects, whose initialization has
|
| 308 |
-
completed
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 314 |
|
| 315 |
If the *compound-statement* of the *function-body* of a delegating
|
| 316 |
constructor for an object exits via an exception, the object’s
|
| 317 |
destructor is invoked. Such destruction is sequenced before entering a
|
| 318 |
handler of the *function-try-block* of a delegating constructor for that
|
| 319 |
object, if any.
|
| 320 |
|
| 321 |
-
[*Note
|
| 322 |
-
[[expr.new]]
|
| 323 |
-
[[basic.stc.dynamic.deallocation]]
|
| 324 |
storage occupied by the object. — *end note*]
|
| 325 |
|
| 326 |
## Handling an exception <a id="except.handle">[[except.handle]]</a>
|
| 327 |
|
| 328 |
The *exception-declaration* in a *handler* describes the type(s) of
|
|
@@ -341,23 +353,23 @@ A *handler* is a match for an exception object of type `E` if
|
|
| 341 |
- The *handler* is of type cv `T` or cv `T&` and `E` and `T` are the
|
| 342 |
same type (ignoring the top-level *cv-qualifier*s), or
|
| 343 |
- the *handler* is of type cv `T` or cv `T&` and `T` is an unambiguous
|
| 344 |
public base class of `E`, or
|
| 345 |
- the *handler* is of type cv `T` or `const T&` where `T` is a pointer
|
| 346 |
-
or pointer
|
| 347 |
type that can be converted to `T` by one or more of
|
| 348 |
-
- a standard pointer conversion
|
| 349 |
-
|
| 350 |
-
- a function pointer conversion
|
| 351 |
-
- a qualification conversion
|
| 352 |
- the *handler* is of type cv `T` or `const T&` where `T` is a pointer
|
| 353 |
-
or pointer
|
| 354 |
|
| 355 |
[*Note 1*: A *throw-expression* whose operand is an integer literal
|
| 356 |
-
with value zero does not match a handler of pointer or pointer
|
| 357 |
type. A handler of reference to array or function type is never a match
|
| 358 |
-
for any exception object
|
| 359 |
|
| 360 |
[*Example 1*:
|
| 361 |
|
| 362 |
``` cpp
|
| 363 |
class Matherr { ... virtual void vf(); };
|
|
@@ -397,44 +409,44 @@ try block.
|
|
| 397 |
|
| 398 |
If no match is found among the handlers for a try block, the search for
|
| 399 |
a matching handler continues in a dynamically surrounding try block of
|
| 400 |
the same thread.
|
| 401 |
|
| 402 |
-
A handler is considered active when initialization is complete for the
|
| 403 |
parameter (if any) of the catch clause.
|
| 404 |
|
| 405 |
[*Note 3*: The stack will have been unwound at that
|
| 406 |
point. — *end note*]
|
| 407 |
|
| 408 |
-
Also, an implicit handler is considered active when
|
| 409 |
-
is entered due to a throw. A handler is no longer
|
| 410 |
-
the catch clause exits.
|
| 411 |
|
| 412 |
The exception with the most recently activated handler that is still
|
| 413 |
active is called the *currently handled exception*.
|
| 414 |
|
| 415 |
-
If no matching handler is found, the function `std::terminate
|
| 416 |
called; whether or not the stack is unwound before this call to
|
| 417 |
-
`std::terminate
|
| 418 |
|
| 419 |
Referring to any non-static member or base class of an object in the
|
| 420 |
handler for a *function-try-block* of a constructor or destructor for
|
| 421 |
that object results in undefined behavior.
|
| 422 |
|
| 423 |
The scope and lifetime of the parameters of a function or constructor
|
| 424 |
extend into the handlers of a *function-try-block*.
|
| 425 |
|
| 426 |
Exceptions thrown in destructors of objects with static storage duration
|
| 427 |
or in constructors of namespace-scope objects with static storage
|
| 428 |
-
duration are not caught by a *function-try-block* on the `main`
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
|
| 434 |
-
If a return statement appears in a handler of the
|
| 435 |
-
of a constructor, the program is ill-formed.
|
| 436 |
|
| 437 |
The currently handled exception is rethrown if control reaches the end
|
| 438 |
of a handler of the *function-try-block* of a constructor or destructor.
|
| 439 |
Otherwise, flowing off the end of the *compound-statement* of a
|
| 440 |
*handler* of a *function-try-block* is equivalent to flowing off the end
|
|
@@ -442,18 +454,19 @@ of the *compound-statement* of that function (see [[stmt.return]]).
|
|
| 442 |
|
| 443 |
The variable declared by the *exception-declaration*, of type cv `T` or
|
| 444 |
cv `T&`, is initialized from the exception object, of type `E`, as
|
| 445 |
follows:
|
| 446 |
|
| 447 |
-
- if `T` is a base class of `E`, the variable is copy-initialized
|
| 448 |
-
[[dcl.init]]
|
| 449 |
exception object;
|
| 450 |
-
- otherwise, the variable is copy-initialized
|
| 451 |
exception object.
|
| 452 |
|
| 453 |
The lifetime of the variable ends when the handler exits, after the
|
| 454 |
-
destruction of any
|
|
|
|
| 455 |
|
| 456 |
When the handler declares an object, any changes to that object will not
|
| 457 |
affect the exception object. When the handler declares a reference to an
|
| 458 |
object, any changes to the referenced object are changes to the
|
| 459 |
exception object and will have effect should that object be rethrown.
|
|
@@ -464,37 +477,34 @@ The predicate indicating whether a function cannot exit via an exception
|
|
| 464 |
is called the *exception specification* of the function. If the
|
| 465 |
predicate is false, the function has a *potentially-throwing exception
|
| 466 |
specification*, otherwise it has a *non-throwing exception
|
| 467 |
specification*. The exception specification is either defined
|
| 468 |
implicitly, or defined explicitly by using a *noexcept-specifier* as a
|
| 469 |
-
suffix of a function declarator
|
| 470 |
|
| 471 |
``` bnf
|
| 472 |
noexcept-specifier:
|
| 473 |
'noexcept' '(' constant-expression ')'
|
| 474 |
'noexcept'
|
| 475 |
-
'throw' '(' ')'
|
| 476 |
```
|
| 477 |
|
| 478 |
In a *noexcept-specifier*, the *constant-expression*, if supplied, shall
|
| 479 |
-
be a contextually converted constant expression of type `bool`
|
| 480 |
-
[[expr.const]]
|
| 481 |
of the function type in which the *noexcept-specifier* appears. A `(`
|
| 482 |
token that follows `noexcept` is part of the *noexcept-specifier* and
|
| 483 |
-
does not commence an initializer
|
| 484 |
-
|
| 485 |
-
|
| 486 |
-
*noexcept-specifier* `throw()` is deprecated ([[depr.except.spec]]),
|
| 487 |
-
and equivalent to the *noexcept-specifier* `noexcept(true)`.
|
| 488 |
|
| 489 |
If a declaration of a function does not have a *noexcept-specifier*, the
|
| 490 |
declaration has a potentially throwing exception specification unless it
|
| 491 |
is a destructor or a deallocation function or is defaulted on its first
|
| 492 |
-
declaration, in which cases the exception
|
| 493 |
below and no other declaration for that function shall have a
|
| 494 |
-
*noexcept-specifier*. In an explicit instantiation
|
| 495 |
-
|
| 496 |
*noexcept-specifier* is specified in an explicit instantiation
|
| 497 |
directive, the exception specification shall be the same as the
|
| 498 |
exception specification of all other declarations of that function. A
|
| 499 |
diagnostic is required only if the exception specifications are not the
|
| 500 |
same within a single translation unit.
|
|
@@ -513,11 +523,11 @@ struct B {
|
|
| 513 |
virtual void g();
|
| 514 |
virtual void h() noexcept = delete;
|
| 515 |
};
|
| 516 |
|
| 517 |
struct D: B {
|
| 518 |
-
void f(); //
|
| 519 |
void g() noexcept; // OK
|
| 520 |
void h() = delete; // OK
|
| 521 |
};
|
| 522 |
```
|
| 523 |
|
|
@@ -525,18 +535,19 @@ The declaration of `D::f` is ill-formed because it has a
|
|
| 525 |
potentially-throwing exception specification, whereas `B::f` has a
|
| 526 |
non-throwing exception specification.
|
| 527 |
|
| 528 |
— *end example*]
|
| 529 |
|
| 530 |
-
Whenever an exception is thrown and the search for a handler
|
| 531 |
-
[[except.handle]]
|
| 532 |
-
non-throwing exception specification, the function `std::terminate
|
| 533 |
-
called
|
| 534 |
|
| 535 |
-
[*Note 1*: An implementation
|
| 536 |
-
because, when executed, it throws or might throw an exception
|
| 537 |
-
function with a non-throwing exception
|
|
|
|
| 538 |
|
| 539 |
[*Example 2*:
|
| 540 |
|
| 541 |
``` cpp
|
| 542 |
extern void f(); // potentially-throwing
|
|
@@ -550,26 +561,26 @@ void g() noexcept {
|
|
| 550 |
The call to `f` is well-formed even though, when called, `f` might throw
|
| 551 |
an exception.
|
| 552 |
|
| 553 |
— *end example*]
|
| 554 |
|
| 555 |
-
An expression
|
| 556 |
|
| 557 |
-
-
|
| 558 |
-
|
| 559 |
potentially-throwing exception specification, or
|
| 560 |
-
-
|
| 561 |
allocation function in a *new-expression*, a constructor for a
|
| 562 |
-
function argument, or a destructor if
|
| 563 |
-
[[intro.execution]])
|
| 564 |
-
-
|
| 565 |
-
-
|
| 566 |
-
requires a runtime check
|
| 567 |
-
-
|
| 568 |
built-in unary `*` operator applied to a pointer to a polymorphic
|
| 569 |
-
class type
|
| 570 |
-
- any of the immediate subexpressions
|
| 571 |
potentially-throwing.
|
| 572 |
|
| 573 |
An implicitly-declared constructor for a class `X`, or a constructor
|
| 574 |
without a *noexcept-specifier* that is defaulted on its first
|
| 575 |
declaration, has a potentially-throwing exception specification if and
|
|
@@ -582,44 +593,51 @@ only if any of the following constructs is potentially-throwing:
|
|
| 582 |
expression, or,
|
| 583 |
- for a default constructor, a default member initializer.
|
| 584 |
|
| 585 |
[*Note 2*: Even though destructors for fully-constructed subobjects are
|
| 586 |
invoked when an exception is thrown during the execution of a
|
| 587 |
-
constructor
|
| 588 |
contribute to the exception specification of the constructor, because an
|
| 589 |
-
exception thrown from such a destructor would call
|
| 590 |
-
rather than escape the constructor ([[except.throw]],
|
| 591 |
[[except.terminate]]). — *end note*]
|
| 592 |
|
| 593 |
The exception specification for an implicitly-declared destructor, or a
|
| 594 |
destructor without a *noexcept-specifier*, is potentially-throwing if
|
| 595 |
and only if any of the destructors for any of its potentially
|
| 596 |
-
constructed
|
|
|
|
|
|
|
| 597 |
|
| 598 |
The exception specification for an implicitly-declared assignment
|
| 599 |
operator, or an assignment-operator without a *noexcept-specifier* that
|
| 600 |
is defaulted on its first declaration, is potentially-throwing if and
|
| 601 |
only if the invocation of any assignment operator in the implicit
|
| 602 |
definition is potentially-throwing.
|
| 603 |
|
| 604 |
-
A deallocation function
|
| 605 |
explicit *noexcept-specifier* has a non-throwing exception
|
| 606 |
specification.
|
| 607 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 608 |
[*Example 3*:
|
| 609 |
|
| 610 |
``` cpp
|
| 611 |
struct A {
|
| 612 |
A(int = (A(5), 0)) noexcept;
|
| 613 |
A(const A&) noexcept;
|
| 614 |
A(A&&) noexcept;
|
| 615 |
~A();
|
| 616 |
};
|
| 617 |
struct B {
|
| 618 |
-
B()
|
| 619 |
B(const B&) = default; // implicit exception specification is noexcept(true)
|
| 620 |
-
B(B&&, int = (throw
|
| 621 |
~B() noexcept(false);
|
| 622 |
};
|
| 623 |
int n = 7;
|
| 624 |
struct D : public A, public B {
|
| 625 |
int * p = new int[n];
|
|
@@ -640,109 +658,112 @@ base class function has a non-throwing exception specification.
|
|
| 640 |
An exception specification is considered to be *needed* when:
|
| 641 |
|
| 642 |
- in an expression, the function is the unique lookup result or the
|
| 643 |
selected member of a set of overloaded functions ([[basic.lookup]],
|
| 644 |
[[over.match]], [[over.over]]);
|
| 645 |
-
- the function is odr-used
|
| 646 |
unevaluated operand, would be odr-used if the expression were
|
| 647 |
potentially-evaluated;
|
| 648 |
- the exception specification is compared to that of another declaration
|
| 649 |
(e.g., an explicit specialization or an overriding virtual function);
|
| 650 |
- the function is defined; or
|
| 651 |
-
- the exception specification is needed for a defaulted
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
| 655 |
-
|
| 656 |
-
|
| 657 |
-
against. — *end note*]
|
| 658 |
|
| 659 |
-
The exception specification of a defaulted
|
| 660 |
-
|
| 661 |
-
|
| 662 |
-
|
| 663 |
|
| 664 |
## Special functions <a id="except.special">[[except.special]]</a>
|
| 665 |
|
| 666 |
-
The function `std::terminate
|
| 667 |
exception handling mechanism for coping with errors related to the
|
| 668 |
exception handling mechanism itself. The function
|
| 669 |
-
`std::current_exception()`
|
| 670 |
-
`std::nested_exception`
|
| 671 |
capture the currently handled exception.
|
| 672 |
|
| 673 |
-
### The `std::terminate
|
| 674 |
|
| 675 |
In some situations exception handling must be abandoned for less subtle
|
| 676 |
error handling techniques.
|
| 677 |
|
| 678 |
[*Note 1*:
|
| 679 |
|
| 680 |
These situations are:
|
| 681 |
|
| 682 |
- when the exception handling mechanism, after completing the
|
| 683 |
initialization of the exception object but before activation of a
|
| 684 |
-
handler for the exception
|
| 685 |
exits via an exception, or
|
| 686 |
- when the exception handling mechanism cannot find a handler for a
|
| 687 |
-
thrown exception
|
| 688 |
-
- when the search for a handler
|
| 689 |
outermost block of a function with a non-throwing exception
|
| 690 |
-
specification
|
| 691 |
-
- when the destruction of an object during stack unwinding
|
| 692 |
-
[[except.ctor]]
|
| 693 |
- when initialization of a non-local variable with static or thread
|
| 694 |
-
storage duration
|
| 695 |
- when destruction of an object with static or thread storage duration
|
| 696 |
-
exits via an exception
|
| 697 |
- when execution of a function registered with `std::atexit` or
|
| 698 |
-
`std::at_quick_exit` exits via an exception
|
| 699 |
-
|
| 700 |
-
|
| 701 |
-
|
| 702 |
-
[[except.throw]]), or
|
| 703 |
- when the function `std::nested_exception::rethrow_nested` is called
|
| 704 |
-
for an object that has captured no exception
|
| 705 |
- when execution of the initial function of a thread exits via an
|
| 706 |
-
exception
|
| 707 |
- for a parallel algorithm whose `ExecutionPolicy` specifies such
|
| 708 |
behavior ([[execpol.seq]], [[execpol.par]], [[execpol.parunseq]]),
|
| 709 |
-
when execution of an element access function
|
| 710 |
-
[[algorithms.parallel.defns]]
|
| 711 |
-
exception
|
| 712 |
-
- when the destructor or the
|
| 713 |
object of type `std::thread` that refers to a joinable thread (
|
| 714 |
-
[[thread.thread.destr]],
|
| 715 |
- when a call to a `wait()`, `wait_until()`, or `wait_for()` function on
|
| 716 |
-
a condition variable ([[thread.condition.condvar]],
|
| 717 |
[[thread.condition.condvarany]]) fails to meet a postcondition.
|
| 718 |
|
| 719 |
— *end note*]
|
| 720 |
|
| 721 |
-
In such cases, `std::terminate
|
| 722 |
-
In the situation where no matching handler is
|
| 723 |
-
*implementation-defined* whether or not the stack is
|
| 724 |
-
`std::terminate
|
| 725 |
-
handler
|
| 726 |
-
function with a non-throwing exception specification
|
| 727 |
it is *implementation-defined* whether the stack is unwound, unwound
|
| 728 |
-
partially, or not unwound at all before `std::terminate
|
| 729 |
-
all other situations, the stack shall not be unwound before
|
| 730 |
-
`std::terminate
|
| 731 |
-
finish stack unwinding prematurely based on a determination
|
| 732 |
-
unwind process will eventually cause a call to
|
|
|
|
| 733 |
|
| 734 |
### The `std::uncaught_exceptions()` function <a id="except.uncaught">[[except.uncaught]]</a>
|
| 735 |
|
| 736 |
An exception is considered uncaught after completing the initialization
|
| 737 |
-
of the exception object
|
| 738 |
-
|
| 739 |
-
|
| 740 |
-
[
|
| 741 |
-
|
| 742 |
-
|
| 743 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 744 |
|
| 745 |
<!-- Link reference definitions -->
|
| 746 |
[algorithms.parallel.defns]: algorithms.md#algorithms.parallel.defns
|
| 747 |
[algorithms.parallel.exceptions]: algorithms.md#algorithms.parallel.exceptions
|
| 748 |
[basic.def.odr]: basic.md#basic.def.odr
|
|
@@ -750,50 +771,53 @@ number of uncaught exceptions in the current thread.
|
|
| 750 |
[basic.start.dynamic]: basic.md#basic.start.dynamic
|
| 751 |
[basic.start.main]: basic.md#basic.start.main
|
| 752 |
[basic.start.term]: basic.md#basic.start.term
|
| 753 |
[basic.stc.dynamic.allocation]: basic.md#basic.stc.dynamic.allocation
|
| 754 |
[basic.stc.dynamic.deallocation]: basic.md#basic.stc.dynamic.deallocation
|
| 755 |
-
[class.
|
| 756 |
-
[class.
|
| 757 |
-
[
|
| 758 |
-
[
|
| 759 |
-
[conv.
|
|
|
|
|
|
|
| 760 |
[dcl.fct]: dcl.md#dcl.fct
|
| 761 |
[dcl.init]: dcl.md#dcl.init
|
| 762 |
-
[depr.except.spec]: future.md#depr.except.spec
|
| 763 |
[except]: #except
|
| 764 |
[except.ctor]: #except.ctor
|
| 765 |
[except.handle]: #except.handle
|
| 766 |
-
[except.nested]:
|
|
|
|
| 767 |
[except.spec]: #except.spec
|
| 768 |
[except.special]: #except.special
|
| 769 |
[except.terminate]: #except.terminate
|
| 770 |
[except.throw]: #except.throw
|
| 771 |
[except.uncaught]: #except.uncaught
|
| 772 |
-
[exception.terminate]:
|
| 773 |
[execpol.par]: utilities.md#execpol.par
|
| 774 |
[execpol.parunseq]: utilities.md#execpol.parunseq
|
| 775 |
[execpol.seq]: utilities.md#execpol.seq
|
| 776 |
[expr.call]: expr.md#expr.call
|
| 777 |
[expr.const]: expr.md#expr.const
|
| 778 |
[expr.dynamic.cast]: expr.md#expr.dynamic.cast
|
| 779 |
[expr.new]: expr.md#expr.new
|
| 780 |
[expr.throw]: expr.md#expr.throw
|
| 781 |
[expr.typeid]: expr.md#expr.typeid
|
| 782 |
[futures]: thread.md#futures
|
| 783 |
-
[intro.execution]:
|
| 784 |
-
[intro.races]:
|
|
|
|
| 785 |
[over.match]: over.md#over.match
|
| 786 |
[over.over]: over.md#over.over
|
| 787 |
-
[propagation]:
|
| 788 |
[stmt.jump]: stmt.md#stmt.jump
|
|
|
|
| 789 |
[stmt.return]: stmt.md#stmt.return
|
| 790 |
-
[stmt.stmt]: stmt.md#stmt.stmt
|
| 791 |
[structure.specifications]: library.md#structure.specifications
|
| 792 |
-
[support.start.term]:
|
| 793 |
[temp.explicit]: temp.md#temp.explicit
|
| 794 |
[thread.condition.condvar]: thread.md#thread.condition.condvar
|
| 795 |
[thread.condition.condvarany]: thread.md#thread.condition.condvarany
|
| 796 |
[thread.thread.assign]: thread.md#thread.thread.assign
|
| 797 |
[thread.thread.constr]: thread.md#thread.thread.constr
|
| 798 |
[thread.thread.destr]: thread.md#thread.thread.destr
|
| 799 |
-
[uncaught.exceptions]:
|
|
|
|
| 1 |
# Exception handling <a id="except">[[except]]</a>
|
| 2 |
|
| 3 |
+
## Preamble <a id="except.pre">[[except.pre]]</a>
|
| 4 |
+
|
| 5 |
Exception handling provides a way of transferring control and
|
| 6 |
information from a point in the execution of a thread to an exception
|
| 7 |
handler associated with a point previously passed by the execution. A
|
| 8 |
handler will be invoked only by throwing an exception in code executed
|
| 9 |
in the handler’s try block or in functions called from the handler’s try
|
|
|
|
| 24 |
handler handler-seqₒₚₜ
|
| 25 |
```
|
| 26 |
|
| 27 |
``` bnf
|
| 28 |
handler:
|
| 29 |
+
'catch' '(' exception-declaration ')' compound-statement
|
| 30 |
```
|
| 31 |
|
| 32 |
``` bnf
|
| 33 |
exception-declaration:
|
| 34 |
attribute-specifier-seqₒₚₜ type-specifier-seq declarator
|
| 35 |
attribute-specifier-seqₒₚₜ type-specifier-seq abstract-declaratorₒₚₜ
|
| 36 |
'...'
|
| 37 |
```
|
| 38 |
|
| 39 |
The optional *attribute-specifier-seq* in an *exception-declaration*
|
| 40 |
+
appertains to the parameter of the catch clause [[except.handle]].
|
| 41 |
|
| 42 |
+
A *try-block* is a *statement* [[stmt.pre]].
|
| 43 |
|
| 44 |
[*Note 1*: Within this Clause “try block” is taken to mean both
|
| 45 |
*try-block* and *function-try-block*. — *end note*]
|
| 46 |
|
| 47 |
A `goto` or `switch` statement shall not be used to transfer control
|
|
|
|
| 49 |
|
| 50 |
[*Example 1*:
|
| 51 |
|
| 52 |
``` cpp
|
| 53 |
void f() {
|
| 54 |
+
goto l1; // error
|
| 55 |
+
goto l2; // error
|
| 56 |
try {
|
| 57 |
goto l1; // OK
|
| 58 |
+
goto l2; // error
|
| 59 |
l1: ;
|
| 60 |
} catch (...) {
|
| 61 |
l2: ;
|
| 62 |
+
goto l1; // error
|
| 63 |
goto l2; // OK
|
| 64 |
}
|
| 65 |
}
|
| 66 |
```
|
| 67 |
|
|
|
|
| 120 |
}
|
| 121 |
```
|
| 122 |
|
| 123 |
— *end example*]
|
| 124 |
|
| 125 |
+
In this Clause, “before” and “after” refer to the “sequenced before”
|
| 126 |
+
relation [[intro.execution]].
|
| 127 |
|
| 128 |
## Throwing an exception <a id="except.throw">[[except.throw]]</a>
|
| 129 |
|
| 130 |
Throwing an exception transfers control to a handler.
|
| 131 |
|
| 132 |
[*Note 1*: An exception can be thrown from one of the following
|
| 133 |
+
contexts: *throw-expression*s [[expr.throw]], allocation functions
|
| 134 |
+
[[basic.stc.dynamic.allocation]], `dynamic_cast` [[expr.dynamic.cast]],
|
| 135 |
+
`typeid` [[expr.typeid]], *new-expression*s [[expr.new]], and standard
|
| 136 |
+
library functions [[structure.specifications]]. — *end note*]
|
|
|
|
| 137 |
|
| 138 |
An object is passed and the type of that object determines which
|
| 139 |
handlers can catch it.
|
| 140 |
|
| 141 |
[*Example 1*:
|
|
|
|
| 178 |
```
|
| 179 |
|
| 180 |
— *end example*]
|
| 181 |
|
| 182 |
When an exception is thrown, control is transferred to the nearest
|
| 183 |
+
handler with a matching type [[except.handle]]; “nearest” means the
|
| 184 |
handler for which the *compound-statement* or *ctor-initializer*
|
| 185 |
following the `try` keyword was most recently entered by the thread of
|
| 186 |
control and not yet exited.
|
| 187 |
|
| 188 |
+
Throwing an exception copy-initializes ([[dcl.init]],
|
| 189 |
+
[[class.copy.ctor]]) a temporary object, called the *exception object*.
|
| 190 |
+
An lvalue denoting the temporary is used to initialize the variable
|
| 191 |
+
declared in the matching *handler* [[except.handle]]. If the type of the
|
| 192 |
+
exception object would be an incomplete type, an abstract class type
|
| 193 |
+
[[class.abstract]], or a pointer to an incomplete type other than
|
| 194 |
+
cv `void` the program is ill-formed.
|
| 195 |
|
| 196 |
The memory for the exception object is allocated in an unspecified way,
|
| 197 |
except as noted in [[basic.stc.dynamic.allocation]]. If a handler exits
|
| 198 |
by rethrowing, control is passed to another handler for the same
|
| 199 |
exception object. The points of potential destruction for the exception
|
| 200 |
object are:
|
| 201 |
|
| 202 |
- when an active handler for the exception exits by any means other than
|
| 203 |
rethrowing, immediately after the destruction of the object (if any)
|
| 204 |
declared in the *exception-declaration* in the handler;
|
| 205 |
+
- when an object of type `std::exception_ptr` [[propagation]] that
|
| 206 |
refers to the exception object is destroyed, before the destructor of
|
| 207 |
`std::exception_ptr` returns.
|
| 208 |
|
| 209 |
Among all points of potential destruction for the exception object,
|
| 210 |
there is an unspecified last one where the exception object is
|
| 211 |
+
destroyed. All other points happen before that last one [[intro.races]].
|
|
|
|
| 212 |
|
| 213 |
[*Note 2*: No other thread synchronization is implied in exception
|
| 214 |
handling. — *end note*]
|
| 215 |
|
| 216 |
The implementation may then deallocate the memory for the exception
|
|
|
|
| 221 |
see [[propagation]] and [[futures]]. — *end note*]
|
| 222 |
|
| 223 |
When the thrown object is a class object, the constructor selected for
|
| 224 |
the copy-initialization as well as the constructor selected for a
|
| 225 |
copy-initialization considering the thrown object as an lvalue shall be
|
| 226 |
+
non-deleted and accessible, even if the copy/move operation is elided
|
| 227 |
+
[[class.copy.elision]]. The destructor is potentially invoked
|
| 228 |
+
[[class.dtor]].
|
| 229 |
|
| 230 |
An exception is considered caught when a handler for that exception
|
| 231 |
+
becomes active [[except.handle]].
|
| 232 |
|
| 233 |
[*Note 4*: An exception can have active handlers and still be
|
| 234 |
considered uncaught if it is rethrown. — *end note*]
|
| 235 |
|
| 236 |
+
If the exception handling mechanism handling an uncaught exception
|
| 237 |
+
[[except.uncaught]] directly invokes a function that exits via an
|
| 238 |
+
exception, the function `std::terminate` is called [[except.terminate]].
|
| 239 |
|
| 240 |
[*Example 2*:
|
| 241 |
|
| 242 |
``` cpp
|
| 243 |
struct C {
|
| 244 |
C() { }
|
| 245 |
C(const C&) {
|
| 246 |
if (std::uncaught_exceptions()) {
|
| 247 |
+
throw 0; // throw during copy to handler's exception-declaration object[except.handle]
|
| 248 |
}
|
| 249 |
}
|
| 250 |
};
|
| 251 |
|
| 252 |
int main() {
|
| 253 |
try {
|
| 254 |
+
throw C(); // calls std::terminate if construction of the handler's
|
| 255 |
+
// exception-declaration object is not elided[class.copy.elision]
|
| 256 |
} catch(C) { }
|
| 257 |
}
|
| 258 |
```
|
| 259 |
|
| 260 |
— *end example*]
|
| 261 |
|
| 262 |
+
[*Note 5*:
|
| 263 |
+
|
| 264 |
+
Consequently, destructors should generally catch exceptions and not let
|
| 265 |
+
them propagate.
|
| 266 |
+
|
| 267 |
+
— *end note*]
|
| 268 |
|
| 269 |
## Constructors and destructors <a id="except.ctor">[[except.ctor]]</a>
|
| 270 |
|
| 271 |
As control passes from the point where an exception is thrown to a
|
| 272 |
+
handler, objects with automatic storage duration are destroyed by a
|
| 273 |
+
process, specified in this subclause, called *stack unwinding*.
|
| 274 |
|
| 275 |
+
Each object with automatic storage duration is destroyed if it has been
|
| 276 |
constructed, but not yet destroyed, since the try block was entered. If
|
| 277 |
an exception is thrown during the destruction of temporaries or local
|
| 278 |
+
variables for a `return` statement [[stmt.return]], the destructor for
|
| 279 |
+
the returned object (if any) is also invoked. The objects are destroyed
|
| 280 |
+
in the reverse order of the completion of their construction.
|
| 281 |
|
| 282 |
[*Example 1*:
|
| 283 |
|
| 284 |
``` cpp
|
| 285 |
struct A { };
|
|
|
|
| 297 |
return {}; // #2
|
| 298 |
}
|
| 299 |
```
|
| 300 |
|
| 301 |
At \#1, the returned object of type `A` is constructed. Then, the local
|
| 302 |
+
variable `b` is destroyed [[stmt.jump]]. Next, the local variable `y` is
|
| 303 |
+
destroyed, causing stack unwinding, resulting in the destruction of the
|
| 304 |
+
returned object, followed by the destruction of the local variable `a`.
|
| 305 |
+
Finally, the returned object is constructed again at \#2.
|
| 306 |
|
| 307 |
— *end example*]
|
| 308 |
|
| 309 |
If the initialization or destruction of an object other than by
|
| 310 |
delegating constructor is terminated by an exception, the destructor is
|
| 311 |
invoked for each of the object’s direct subobjects and, for a complete
|
| 312 |
object, virtual base class subobjects, whose initialization has
|
| 313 |
+
completed [[dcl.init]] and whose destructor has not yet begun execution,
|
| 314 |
+
except that in the case of destruction, the variant members of a
|
| 315 |
+
union-like class are not destroyed.
|
| 316 |
+
|
| 317 |
+
[*Note 1*: If such an object has a reference member that extends the
|
| 318 |
+
lifetime of a temporary object, this ends the lifetime of the reference
|
| 319 |
+
member, so the lifetime of the temporary object is effectively not
|
| 320 |
+
extended. — *end note*]
|
| 321 |
+
|
| 322 |
+
The subobjects are destroyed in the reverse order of the completion of
|
| 323 |
+
their construction. Such destruction is sequenced before entering a
|
| 324 |
+
handler of the *function-try-block* of the constructor or destructor, if
|
| 325 |
+
any.
|
| 326 |
|
| 327 |
If the *compound-statement* of the *function-body* of a delegating
|
| 328 |
constructor for an object exits via an exception, the object’s
|
| 329 |
destructor is invoked. Such destruction is sequenced before entering a
|
| 330 |
handler of the *function-try-block* of a delegating constructor for that
|
| 331 |
object, if any.
|
| 332 |
|
| 333 |
+
[*Note 2*: If the object was allocated by a *new-expression*
|
| 334 |
+
[[expr.new]], the matching deallocation function
|
| 335 |
+
[[basic.stc.dynamic.deallocation]], if any, is called to free the
|
| 336 |
storage occupied by the object. — *end note*]
|
| 337 |
|
| 338 |
## Handling an exception <a id="except.handle">[[except.handle]]</a>
|
| 339 |
|
| 340 |
The *exception-declaration* in a *handler* describes the type(s) of
|
|
|
|
| 353 |
- The *handler* is of type cv `T` or cv `T&` and `E` and `T` are the
|
| 354 |
same type (ignoring the top-level *cv-qualifier*s), or
|
| 355 |
- the *handler* is of type cv `T` or cv `T&` and `T` is an unambiguous
|
| 356 |
public base class of `E`, or
|
| 357 |
- the *handler* is of type cv `T` or `const T&` where `T` is a pointer
|
| 358 |
+
or pointer-to-member type and `E` is a pointer or pointer-to-member
|
| 359 |
type that can be converted to `T` by one or more of
|
| 360 |
+
- a standard pointer conversion [[conv.ptr]] not involving conversions
|
| 361 |
+
to pointers to private or protected or ambiguous classes
|
| 362 |
+
- a function pointer conversion [[conv.fctptr]]
|
| 363 |
+
- a qualification conversion [[conv.qual]], or
|
| 364 |
- the *handler* is of type cv `T` or `const T&` where `T` is a pointer
|
| 365 |
+
or pointer-to-member type and `E` is `std::nullptr_t`.
|
| 366 |
|
| 367 |
[*Note 1*: A *throw-expression* whose operand is an integer literal
|
| 368 |
+
with value zero does not match a handler of pointer or pointer-to-member
|
| 369 |
type. A handler of reference to array or function type is never a match
|
| 370 |
+
for any exception object [[expr.throw]]. — *end note*]
|
| 371 |
|
| 372 |
[*Example 1*:
|
| 373 |
|
| 374 |
``` cpp
|
| 375 |
class Matherr { ... virtual void vf(); };
|
|
|
|
| 409 |
|
| 410 |
If no match is found among the handlers for a try block, the search for
|
| 411 |
a matching handler continues in a dynamically surrounding try block of
|
| 412 |
the same thread.
|
| 413 |
|
| 414 |
+
A handler is considered *active* when initialization is complete for the
|
| 415 |
parameter (if any) of the catch clause.
|
| 416 |
|
| 417 |
[*Note 3*: The stack will have been unwound at that
|
| 418 |
point. — *end note*]
|
| 419 |
|
| 420 |
+
Also, an implicit handler is considered active when the function
|
| 421 |
+
`std::terminate` is entered due to a throw. A handler is no longer
|
| 422 |
+
considered active when the catch clause exits.
|
| 423 |
|
| 424 |
The exception with the most recently activated handler that is still
|
| 425 |
active is called the *currently handled exception*.
|
| 426 |
|
| 427 |
+
If no matching handler is found, the function `std::terminate` is
|
| 428 |
called; whether or not the stack is unwound before this call to
|
| 429 |
+
`std::terminate` is *implementation-defined* [[except.terminate]].
|
| 430 |
|
| 431 |
Referring to any non-static member or base class of an object in the
|
| 432 |
handler for a *function-try-block* of a constructor or destructor for
|
| 433 |
that object results in undefined behavior.
|
| 434 |
|
| 435 |
The scope and lifetime of the parameters of a function or constructor
|
| 436 |
extend into the handlers of a *function-try-block*.
|
| 437 |
|
| 438 |
Exceptions thrown in destructors of objects with static storage duration
|
| 439 |
or in constructors of namespace-scope objects with static storage
|
| 440 |
+
duration are not caught by a *function-try-block* on the `main` function
|
| 441 |
+
[[basic.start.main]]. Exceptions thrown in destructors of objects with
|
| 442 |
+
thread storage duration or in constructors of namespace-scope objects
|
| 443 |
+
with thread storage duration are not caught by a *function-try-block* on
|
| 444 |
+
the initial function of the thread.
|
| 445 |
|
| 446 |
+
If a `return` statement [[stmt.return]] appears in a handler of the
|
| 447 |
+
*function-try-block* of a constructor, the program is ill-formed.
|
| 448 |
|
| 449 |
The currently handled exception is rethrown if control reaches the end
|
| 450 |
of a handler of the *function-try-block* of a constructor or destructor.
|
| 451 |
Otherwise, flowing off the end of the *compound-statement* of a
|
| 452 |
*handler* of a *function-try-block* is equivalent to flowing off the end
|
|
|
|
| 454 |
|
| 455 |
The variable declared by the *exception-declaration*, of type cv `T` or
|
| 456 |
cv `T&`, is initialized from the exception object, of type `E`, as
|
| 457 |
follows:
|
| 458 |
|
| 459 |
+
- if `T` is a base class of `E`, the variable is copy-initialized
|
| 460 |
+
[[dcl.init]] from the corresponding base class subobject of the
|
| 461 |
exception object;
|
| 462 |
+
- otherwise, the variable is copy-initialized [[dcl.init]] from the
|
| 463 |
exception object.
|
| 464 |
|
| 465 |
The lifetime of the variable ends when the handler exits, after the
|
| 466 |
+
destruction of any objects with automatic storage duration initialized
|
| 467 |
+
within the handler.
|
| 468 |
|
| 469 |
When the handler declares an object, any changes to that object will not
|
| 470 |
affect the exception object. When the handler declares a reference to an
|
| 471 |
object, any changes to the referenced object are changes to the
|
| 472 |
exception object and will have effect should that object be rethrown.
|
|
|
|
| 477 |
is called the *exception specification* of the function. If the
|
| 478 |
predicate is false, the function has a *potentially-throwing exception
|
| 479 |
specification*, otherwise it has a *non-throwing exception
|
| 480 |
specification*. The exception specification is either defined
|
| 481 |
implicitly, or defined explicitly by using a *noexcept-specifier* as a
|
| 482 |
+
suffix of a function declarator [[dcl.fct]].
|
| 483 |
|
| 484 |
``` bnf
|
| 485 |
noexcept-specifier:
|
| 486 |
'noexcept' '(' constant-expression ')'
|
| 487 |
'noexcept'
|
|
|
|
| 488 |
```
|
| 489 |
|
| 490 |
In a *noexcept-specifier*, the *constant-expression*, if supplied, shall
|
| 491 |
+
be a contextually converted constant expression of type `bool`
|
| 492 |
+
[[expr.const]]; that constant expression is the exception specification
|
| 493 |
of the function type in which the *noexcept-specifier* appears. A `(`
|
| 494 |
token that follows `noexcept` is part of the *noexcept-specifier* and
|
| 495 |
+
does not commence an initializer [[dcl.init]]. The *noexcept-specifier*
|
| 496 |
+
`noexcept` without a *constant-expression* is equivalent to the
|
| 497 |
+
*noexcept-specifier* `noexcept(true)`.
|
|
|
|
|
|
|
| 498 |
|
| 499 |
If a declaration of a function does not have a *noexcept-specifier*, the
|
| 500 |
declaration has a potentially throwing exception specification unless it
|
| 501 |
is a destructor or a deallocation function or is defaulted on its first
|
| 502 |
+
declaration, in which cases the exception specification is as specified
|
| 503 |
below and no other declaration for that function shall have a
|
| 504 |
+
*noexcept-specifier*. In an explicit instantiation [[temp.explicit]] a
|
| 505 |
+
*noexcept-specifier* may be specified, but is not required. If a
|
| 506 |
*noexcept-specifier* is specified in an explicit instantiation
|
| 507 |
directive, the exception specification shall be the same as the
|
| 508 |
exception specification of all other declarations of that function. A
|
| 509 |
diagnostic is required only if the exception specifications are not the
|
| 510 |
same within a single translation unit.
|
|
|
|
| 523 |
virtual void g();
|
| 524 |
virtual void h() noexcept = delete;
|
| 525 |
};
|
| 526 |
|
| 527 |
struct D: B {
|
| 528 |
+
void f(); // error
|
| 529 |
void g() noexcept; // OK
|
| 530 |
void h() = delete; // OK
|
| 531 |
};
|
| 532 |
```
|
| 533 |
|
|
|
|
| 535 |
potentially-throwing exception specification, whereas `B::f` has a
|
| 536 |
non-throwing exception specification.
|
| 537 |
|
| 538 |
— *end example*]
|
| 539 |
|
| 540 |
+
Whenever an exception is thrown and the search for a handler
|
| 541 |
+
[[except.handle]] encounters the outermost block of a function with a
|
| 542 |
+
non-throwing exception specification, the function `std::terminate` is
|
| 543 |
+
called [[except.terminate]].
|
| 544 |
|
| 545 |
+
[*Note 1*: An implementation is not permitted to reject an expression
|
| 546 |
+
merely because, when executed, it throws or might throw an exception
|
| 547 |
+
from a function with a non-throwing exception
|
| 548 |
+
specification. — *end note*]
|
| 549 |
|
| 550 |
[*Example 2*:
|
| 551 |
|
| 552 |
``` cpp
|
| 553 |
extern void f(); // potentially-throwing
|
|
|
|
| 561 |
The call to `f` is well-formed even though, when called, `f` might throw
|
| 562 |
an exception.
|
| 563 |
|
| 564 |
— *end example*]
|
| 565 |
|
| 566 |
+
An expression E is *potentially-throwing* if
|
| 567 |
|
| 568 |
+
- E is a function call [[expr.call]] whose *postfix-expression* has a
|
| 569 |
+
function type, or a pointer-to-function type, with a
|
| 570 |
potentially-throwing exception specification, or
|
| 571 |
+
- E implicitly invokes a function (such as an overloaded operator, an
|
| 572 |
allocation function in a *new-expression*, a constructor for a
|
| 573 |
+
function argument, or a destructor if E is a full-expression
|
| 574 |
+
[[intro.execution]]) that is potentially-throwing, or
|
| 575 |
+
- E is a *throw-expression* [[expr.throw]], or
|
| 576 |
+
- E is a `dynamic_cast` expression that casts to a reference type and
|
| 577 |
+
requires a runtime check [[expr.dynamic.cast]], or
|
| 578 |
+
- E is a `typeid` expression applied to a (possibly parenthesized)
|
| 579 |
built-in unary `*` operator applied to a pointer to a polymorphic
|
| 580 |
+
class type [[expr.typeid]], or
|
| 581 |
+
- any of the immediate subexpressions [[intro.execution]] of E is
|
| 582 |
potentially-throwing.
|
| 583 |
|
| 584 |
An implicitly-declared constructor for a class `X`, or a constructor
|
| 585 |
without a *noexcept-specifier* that is defaulted on its first
|
| 586 |
declaration, has a potentially-throwing exception specification if and
|
|
|
|
| 593 |
expression, or,
|
| 594 |
- for a default constructor, a default member initializer.
|
| 595 |
|
| 596 |
[*Note 2*: Even though destructors for fully-constructed subobjects are
|
| 597 |
invoked when an exception is thrown during the execution of a
|
| 598 |
+
constructor [[except.ctor]], their exception specifications do not
|
| 599 |
contribute to the exception specification of the constructor, because an
|
| 600 |
+
exception thrown from such a destructor would call the function
|
| 601 |
+
`std::terminate` rather than escape the constructor ([[except.throw]],
|
| 602 |
[[except.terminate]]). — *end note*]
|
| 603 |
|
| 604 |
The exception specification for an implicitly-declared destructor, or a
|
| 605 |
destructor without a *noexcept-specifier*, is potentially-throwing if
|
| 606 |
and only if any of the destructors for any of its potentially
|
| 607 |
+
constructed subobjects is potentially-throwing or the destructor is
|
| 608 |
+
virtual and the destructor of any virtual base class is
|
| 609 |
+
potentially-throwing.
|
| 610 |
|
| 611 |
The exception specification for an implicitly-declared assignment
|
| 612 |
operator, or an assignment-operator without a *noexcept-specifier* that
|
| 613 |
is defaulted on its first declaration, is potentially-throwing if and
|
| 614 |
only if the invocation of any assignment operator in the implicit
|
| 615 |
definition is potentially-throwing.
|
| 616 |
|
| 617 |
+
A deallocation function [[basic.stc.dynamic.deallocation]] with no
|
| 618 |
explicit *noexcept-specifier* has a non-throwing exception
|
| 619 |
specification.
|
| 620 |
|
| 621 |
+
The exception specification for a comparison operator function
|
| 622 |
+
[[over.binary]] without a *noexcept-specifier* that is defaulted on its
|
| 623 |
+
first declaration is potentially-throwing if and only if any expression
|
| 624 |
+
in the implicit definition is potentially-throwing.
|
| 625 |
+
|
| 626 |
[*Example 3*:
|
| 627 |
|
| 628 |
``` cpp
|
| 629 |
struct A {
|
| 630 |
A(int = (A(5), 0)) noexcept;
|
| 631 |
A(const A&) noexcept;
|
| 632 |
A(A&&) noexcept;
|
| 633 |
~A();
|
| 634 |
};
|
| 635 |
struct B {
|
| 636 |
+
B() noexcept;
|
| 637 |
B(const B&) = default; // implicit exception specification is noexcept(true)
|
| 638 |
+
B(B&&, int = (throw 42, 0)) noexcept;
|
| 639 |
~B() noexcept(false);
|
| 640 |
};
|
| 641 |
int n = 7;
|
| 642 |
struct D : public A, public B {
|
| 643 |
int * p = new int[n];
|
|
|
|
| 658 |
An exception specification is considered to be *needed* when:
|
| 659 |
|
| 660 |
- in an expression, the function is the unique lookup result or the
|
| 661 |
selected member of a set of overloaded functions ([[basic.lookup]],
|
| 662 |
[[over.match]], [[over.over]]);
|
| 663 |
+
- the function is odr-used [[basic.def.odr]] or, if it appears in an
|
| 664 |
unevaluated operand, would be odr-used if the expression were
|
| 665 |
potentially-evaluated;
|
| 666 |
- the exception specification is compared to that of another declaration
|
| 667 |
(e.g., an explicit specialization or an overriding virtual function);
|
| 668 |
- the function is defined; or
|
| 669 |
+
- the exception specification is needed for a defaulted function that
|
| 670 |
+
calls the function. \[*Note 3*: A defaulted declaration does not
|
| 671 |
+
require the exception specification of a base member function to be
|
| 672 |
+
evaluated until the implicit exception specification of the derived
|
| 673 |
+
function is needed, but an explicit *noexcept-specifier* needs the
|
| 674 |
+
implicit exception specification to compare against. — *end note*]
|
|
|
|
| 675 |
|
| 676 |
+
The exception specification of a defaulted function is evaluated as
|
| 677 |
+
described above only when needed; similarly, the *noexcept-specifier* of
|
| 678 |
+
a specialization of a function template or member function of a class
|
| 679 |
+
template is instantiated only when needed.
|
| 680 |
|
| 681 |
## Special functions <a id="except.special">[[except.special]]</a>
|
| 682 |
|
| 683 |
+
The function `std::terminate` [[except.terminate]] is used by the
|
| 684 |
exception handling mechanism for coping with errors related to the
|
| 685 |
exception handling mechanism itself. The function
|
| 686 |
+
`std::current_exception()` [[propagation]] and the class
|
| 687 |
+
`std::nested_exception` [[except.nested]] can be used by a program to
|
| 688 |
capture the currently handled exception.
|
| 689 |
|
| 690 |
+
### The `std::terminate` function <a id="except.terminate">[[except.terminate]]</a>
|
| 691 |
|
| 692 |
In some situations exception handling must be abandoned for less subtle
|
| 693 |
error handling techniques.
|
| 694 |
|
| 695 |
[*Note 1*:
|
| 696 |
|
| 697 |
These situations are:
|
| 698 |
|
| 699 |
- when the exception handling mechanism, after completing the
|
| 700 |
initialization of the exception object but before activation of a
|
| 701 |
+
handler for the exception [[except.throw]], calls a function that
|
| 702 |
exits via an exception, or
|
| 703 |
- when the exception handling mechanism cannot find a handler for a
|
| 704 |
+
thrown exception [[except.handle]], or
|
| 705 |
+
- when the search for a handler [[except.handle]] encounters the
|
| 706 |
outermost block of a function with a non-throwing exception
|
| 707 |
+
specification [[except.spec]], or
|
| 708 |
+
- when the destruction of an object during stack unwinding
|
| 709 |
+
[[except.ctor]] terminates by throwing an exception, or
|
| 710 |
- when initialization of a non-local variable with static or thread
|
| 711 |
+
storage duration [[basic.start.dynamic]] exits via an exception, or
|
| 712 |
- when destruction of an object with static or thread storage duration
|
| 713 |
+
exits via an exception [[basic.start.term]], or
|
| 714 |
- when execution of a function registered with `std::atexit` or
|
| 715 |
+
`std::at_quick_exit` exits via an exception [[support.start.term]], or
|
| 716 |
+
- when a *throw-expression* [[expr.throw]] with no operand attempts to
|
| 717 |
+
rethrow an exception and no exception is being handled
|
| 718 |
+
[[except.throw]], or
|
|
|
|
| 719 |
- when the function `std::nested_exception::rethrow_nested` is called
|
| 720 |
+
for an object that has captured no exception [[except.nested]], or
|
| 721 |
- when execution of the initial function of a thread exits via an
|
| 722 |
+
exception [[thread.thread.constr]], or
|
| 723 |
- for a parallel algorithm whose `ExecutionPolicy` specifies such
|
| 724 |
behavior ([[execpol.seq]], [[execpol.par]], [[execpol.parunseq]]),
|
| 725 |
+
when execution of an element access function
|
| 726 |
+
[[algorithms.parallel.defns]] of the parallel algorithm exits via an
|
| 727 |
+
exception [[algorithms.parallel.exceptions]], or
|
| 728 |
+
- when the destructor or the move assignment operator is invoked on an
|
| 729 |
object of type `std::thread` that refers to a joinable thread (
|
| 730 |
+
[[thread.thread.destr]], [[thread.thread.assign]]), or
|
| 731 |
- when a call to a `wait()`, `wait_until()`, or `wait_for()` function on
|
| 732 |
+
a condition variable ([[thread.condition.condvar]],
|
| 733 |
[[thread.condition.condvarany]]) fails to meet a postcondition.
|
| 734 |
|
| 735 |
— *end note*]
|
| 736 |
|
| 737 |
+
In such cases, the function `std::terminate` is called
|
| 738 |
+
[[exception.terminate]]. In the situation where no matching handler is
|
| 739 |
+
found, it is *implementation-defined* whether or not the stack is
|
| 740 |
+
unwound before `std::terminate` is called. In the situation where the
|
| 741 |
+
search for a handler [[except.handle]] encounters the outermost block of
|
| 742 |
+
a function with a non-throwing exception specification [[except.spec]],
|
| 743 |
it is *implementation-defined* whether the stack is unwound, unwound
|
| 744 |
+
partially, or not unwound at all before the function `std::terminate` is
|
| 745 |
+
called. In all other situations, the stack shall not be unwound before
|
| 746 |
+
the function `std::terminate` is called. An implementation is not
|
| 747 |
+
permitted to finish stack unwinding prematurely based on a determination
|
| 748 |
+
that the unwind process will eventually cause a call to the function
|
| 749 |
+
`std::terminate`.
|
| 750 |
|
| 751 |
### The `std::uncaught_exceptions()` function <a id="except.uncaught">[[except.uncaught]]</a>
|
| 752 |
|
| 753 |
An exception is considered uncaught after completing the initialization
|
| 754 |
+
of the exception object [[except.throw]] until completing the activation
|
| 755 |
+
of a handler for the exception [[except.handle]].
|
| 756 |
+
|
| 757 |
+
[*Note 1*: As a consequence, an exception is considered uncaught during
|
| 758 |
+
any stack unwinding resulting from it being thrown. — *end note*]
|
| 759 |
+
|
| 760 |
+
If an exception is rethrown ([[expr.throw]], [[propagation]]), it is
|
| 761 |
+
considered uncaught from the point of rethrow until the rethrown
|
| 762 |
+
exception is caught. The function `std::uncaught_exceptions()`
|
| 763 |
+
[[uncaught.exceptions]] returns the number of uncaught exceptions in the
|
| 764 |
+
current thread.
|
| 765 |
|
| 766 |
<!-- Link reference definitions -->
|
| 767 |
[algorithms.parallel.defns]: algorithms.md#algorithms.parallel.defns
|
| 768 |
[algorithms.parallel.exceptions]: algorithms.md#algorithms.parallel.exceptions
|
| 769 |
[basic.def.odr]: basic.md#basic.def.odr
|
|
|
|
| 771 |
[basic.start.dynamic]: basic.md#basic.start.dynamic
|
| 772 |
[basic.start.main]: basic.md#basic.start.main
|
| 773 |
[basic.start.term]: basic.md#basic.start.term
|
| 774 |
[basic.stc.dynamic.allocation]: basic.md#basic.stc.dynamic.allocation
|
| 775 |
[basic.stc.dynamic.deallocation]: basic.md#basic.stc.dynamic.deallocation
|
| 776 |
+
[class.abstract]: class.md#class.abstract
|
| 777 |
+
[class.copy.ctor]: class.md#class.copy.ctor
|
| 778 |
+
[class.copy.elision]: class.md#class.copy.elision
|
| 779 |
+
[class.dtor]: class.md#class.dtor
|
| 780 |
+
[conv.fctptr]: expr.md#conv.fctptr
|
| 781 |
+
[conv.ptr]: expr.md#conv.ptr
|
| 782 |
+
[conv.qual]: expr.md#conv.qual
|
| 783 |
[dcl.fct]: dcl.md#dcl.fct
|
| 784 |
[dcl.init]: dcl.md#dcl.init
|
|
|
|
| 785 |
[except]: #except
|
| 786 |
[except.ctor]: #except.ctor
|
| 787 |
[except.handle]: #except.handle
|
| 788 |
+
[except.nested]: support.md#except.nested
|
| 789 |
+
[except.pre]: #except.pre
|
| 790 |
[except.spec]: #except.spec
|
| 791 |
[except.special]: #except.special
|
| 792 |
[except.terminate]: #except.terminate
|
| 793 |
[except.throw]: #except.throw
|
| 794 |
[except.uncaught]: #except.uncaught
|
| 795 |
+
[exception.terminate]: support.md#exception.terminate
|
| 796 |
[execpol.par]: utilities.md#execpol.par
|
| 797 |
[execpol.parunseq]: utilities.md#execpol.parunseq
|
| 798 |
[execpol.seq]: utilities.md#execpol.seq
|
| 799 |
[expr.call]: expr.md#expr.call
|
| 800 |
[expr.const]: expr.md#expr.const
|
| 801 |
[expr.dynamic.cast]: expr.md#expr.dynamic.cast
|
| 802 |
[expr.new]: expr.md#expr.new
|
| 803 |
[expr.throw]: expr.md#expr.throw
|
| 804 |
[expr.typeid]: expr.md#expr.typeid
|
| 805 |
[futures]: thread.md#futures
|
| 806 |
+
[intro.execution]: basic.md#intro.execution
|
| 807 |
+
[intro.races]: basic.md#intro.races
|
| 808 |
+
[over.binary]: over.md#over.binary
|
| 809 |
[over.match]: over.md#over.match
|
| 810 |
[over.over]: over.md#over.over
|
| 811 |
+
[propagation]: support.md#propagation
|
| 812 |
[stmt.jump]: stmt.md#stmt.jump
|
| 813 |
+
[stmt.pre]: stmt.md#stmt.pre
|
| 814 |
[stmt.return]: stmt.md#stmt.return
|
|
|
|
| 815 |
[structure.specifications]: library.md#structure.specifications
|
| 816 |
+
[support.start.term]: support.md#support.start.term
|
| 817 |
[temp.explicit]: temp.md#temp.explicit
|
| 818 |
[thread.condition.condvar]: thread.md#thread.condition.condvar
|
| 819 |
[thread.condition.condvarany]: thread.md#thread.condition.condvarany
|
| 820 |
[thread.thread.assign]: thread.md#thread.thread.assign
|
| 821 |
[thread.thread.constr]: thread.md#thread.thread.constr
|
| 822 |
[thread.thread.destr]: thread.md#thread.thread.destr
|
| 823 |
+
[uncaught.exceptions]: support.md#uncaught.exceptions
|