Started some work on it.
The main section is duplicated because I want to use it as a template, to fill in a few other sections.
This commit is contained in:
@@ -0,0 +1,571 @@
|
|||||||
|
# `double static noexcept` -- a mechanism for static checking of noexcept blocks
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. Abstract
|
||||||
|
2. Discussion
|
||||||
|
3. Proposal
|
||||||
|
3. Examples
|
||||||
|
|
||||||
|
## Abstract
|
||||||
|
|
||||||
|
In C++, `noexcept` exists to indicate that a function does not throw an exception. However,
|
||||||
|
what it actually provides is that a function cannot possibly throw an exception. This is
|
||||||
|
enforced by "violence", if necessary -- the program will terminate rather than allow
|
||||||
|
an exception to pass a `noexcept` boundary. Unfortunately, this turns `noexcept` into a
|
||||||
|
ticking timebomb; any `noexcept( true )` function may unexpectedly call `std::terminate`
|
||||||
|
at any time, thus aborting a program. This may be undesirable in many different contexts,
|
||||||
|
from Functional Safety to Program Correctness to Contractual Guarantees. This proposal
|
||||||
|
provides a mechanism which permits various levels of static guarantees.
|
||||||
|
|
||||||
|
## Discussion
|
||||||
|
|
||||||
|
The `noexcept` facility was added to permit a language level (and type-system level)
|
||||||
|
facility for promising that a function does not throw and for checking it. However, the
|
||||||
|
enforcement of this promise is a purely runtime concern. This leads to troublesome
|
||||||
|
timebombs, such as this code.
|
||||||
|
|
||||||
|
~~~
|
||||||
|
void silentlyThrowing() noexcept( false ) { throw 0; }
|
||||||
|
|
||||||
|
void
|
||||||
|
tickingTimeBomb() noexcept( true )
|
||||||
|
{
|
||||||
|
if( not ( rand() % 32 ) )
|
||||||
|
{
|
||||||
|
silentlyThrowing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Result { Success, Failure };
|
||||||
|
|
||||||
|
Result
|
||||||
|
cannotTolerateExceptions() noexcept( true )
|
||||||
|
{
|
||||||
|
std::string element;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
element= someVector.at( 42 );
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::cerr << "Something went wrong" << std::endl;
|
||||||
|
}
|
||||||
|
catch( ... ) { /* Failure to log is troublesome but not fatal */ }
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
someVector.push_back( std::move( element ) );
|
||||||
|
tickingTimeBomb();
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
While some of the code and functions called in `cannotTolerateExceptions` is capable of
|
||||||
|
throwing, the caller attempts to resolve exceptions and handle them without program
|
||||||
|
termination. However, the `tickingTimeBomb` function is a hidden hazard. While
|
||||||
|
it declares itself to not throw exceptions (which is true), the exceptions thrown
|
||||||
|
by code it calls are not checked and will "bump into" the `noexcept( true )`
|
||||||
|
on `tickingTimeBomb`. As such, the program will terminate, despite the best efforts
|
||||||
|
of the `cannotTolerateExceptions()` implementation. The language requires a mechanism
|
||||||
|
to statically check whether callees are equally "responsible" about termination
|
||||||
|
semantics as the caller.
|
||||||
|
|
||||||
|
To this end, we propose three new mechanisms.
|
||||||
|
|
||||||
|
## Proposal
|
||||||
|
|
||||||
|
We propose a few "extensions" to the `noexcept` keyword used on function declarators.
|
||||||
|
We will outline these here.
|
||||||
|
|
||||||
|
##### Note about keyword bikeshedding
|
||||||
|
|
||||||
|
|
||||||
|
This paper proposes "compound" keywords by recycling the meaning of existing keywords.
|
||||||
|
The actual keyword or keyword sequences to define these kinds of `noexcept` function are
|
||||||
|
immaterial to the mechanics of this proposal and thus we defer the decision of keywords
|
||||||
|
at this time.
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
### First new feature A statically checked `noexcept` function - `static noexcept( true )`
|
||||||
|
|
||||||
|
We propose the introduction of `static noexcept` as both a function declaration
|
||||||
|
"decorator" and an operator. `static noexcept( true )` or `static noexcept`
|
||||||
|
tagged functions have similar semantics to `noexcept` tagged or colored functions:
|
||||||
|
|
||||||
|
- An evaluation of `noexcept( someStaticNoexceptFunction )` will evaluate as `true`.
|
||||||
|
- An evaluation of `static noexcept( someStaticNoexceptFunction )` will evaluate as `true`.
|
||||||
|
- An evaluation of `static noexcept( someClassicNoexceptFunction )` will evaluate as `false`.
|
||||||
|
- A call to a `static noexcept( true )` function will not throw.
|
||||||
|
- If an exception unwind (somehow) attempts to "emerge" from a
|
||||||
|
`static noexcept( true )` function, then the program will terminate.
|
||||||
|
|
||||||
|
However, we propose to add the following behaviors and restrictions to such functions:
|
||||||
|
|
||||||
|
- If a `noexcept( false )` function is called outside of the body of a `try` block,
|
||||||
|
then the program is ill formed, and a compile-time diagnostic is required.
|
||||||
|
- If a `noexcept( false )` function is called inside the body of a `try` block, then
|
||||||
|
a `catch( ... )` block must exist.
|
||||||
|
- A `catch` block's body is not considered part of a `try` block.
|
||||||
|
- When checking if a statement is "in" a `try` block, one must walk up the nested
|
||||||
|
block structure until a try block is reached. A `catch` block attached to a
|
||||||
|
`try` block which is inside of a try block at broader scope is considered to be
|
||||||
|
"inside" the broader try block, for the purpose of these rules.
|
||||||
|
- A simple model of this is that invoking `noexcept( false )` functions is ill formed
|
||||||
|
unless a `try` block scope can be found by walking outward from the calling scope.
|
||||||
|
- It is unclear at this time if language UB on expressions should be considered
|
||||||
|
throwing or not. There are tradeoffs.
|
||||||
|
- If UB is considered `noexcept( true )`, then there is a potential that UB
|
||||||
|
can cause program termination by "leaking" an exception out from checked
|
||||||
|
try blocks.
|
||||||
|
- If UB is considered `noexcept( false )`, then it makes writing
|
||||||
|
`static noexcept( true )` extremely difficult. Many situations will
|
||||||
|
require noisy and defensive
|
||||||
|
`try { /* code */ } catch( ... ) { /* silently ignore exception and do nothing */ }`
|
||||||
|
patterns.
|
||||||
|
|
||||||
|
The authors of this paper favor the interpretation that UB and language primitive behavior
|
||||||
|
should be considered `noexcept( true )` for the purpose of this checking. There already
|
||||||
|
exists the possibility of "deeper down" time bombs in this construct and language UB
|
||||||
|
leading to exceptions is a somewhat niche case.
|
||||||
|
|
||||||
|
#### Rewriting the original painful example using this feature
|
||||||
|
|
||||||
|
~~~
|
||||||
|
void silentlyThrowing() noexcept( false ) { throw 0; }
|
||||||
|
|
||||||
|
void
|
||||||
|
tickingTimeBomb() noexcept( true )
|
||||||
|
{
|
||||||
|
if( not ( rand() % 32 ) )
|
||||||
|
{
|
||||||
|
silentlyThrowing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Result { Success, Failure };
|
||||||
|
|
||||||
|
Result
|
||||||
|
illFormedCannotTolerateExceptions() static noexcept( true )
|
||||||
|
{
|
||||||
|
std::string element;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
element= someVector.at( 42 );
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::cerr << "Something went wrong" << std::endl;
|
||||||
|
}
|
||||||
|
catch( ... ) { /* Failure to log is troublesome but not fatal */ }
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
someVector.push_back( std::move( element ) ); // This line would be ill formed
|
||||||
|
tickingTimeBomb();
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result
|
||||||
|
cannotTolerateExceptions() static noexcept( true )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto element= someVector.at( 42 );
|
||||||
|
|
||||||
|
// This line has to be moved into the try block to satisfy the `static noexcept`
|
||||||
|
// requirements
|
||||||
|
someVector.push_back( std::move( element ) );
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::cerr << "Something went wrong" << std::endl;
|
||||||
|
}
|
||||||
|
catch( ... ) { /* Failure to log is troublesome but not fatal */ }
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
tickingTimeBomb();
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
### Second new feature: A stronger (strawman) statically checked function - `false static noexcept( true )`
|
||||||
|
|
||||||
|
Because the troublesome `tickingTimeBomb` function, which was marked `noexcept` still
|
||||||
|
could be called, it's clear that `static noexcept` is insufficiently "sharp" as to catch
|
||||||
|
all time bombs. Yet is still has utility as a tool to help carefully construct functions
|
||||||
|
which are more resilient to unexpected termination. That form provides a comfortable middle
|
||||||
|
ground for many cases. This will become apparent when we introduce our stronger checking mechanisms,
|
||||||
|
`false static noexcept` and `double static noexcept`. It should be noted that
|
||||||
|
`false static noexcept` is a "straw man". It appears to be the correct solution, but it
|
||||||
|
still has traps. We present this one before our real solution, `double static noexcept`. This
|
||||||
|
solution helps expose and explore the problem space.
|
||||||
|
|
||||||
|
For the `false static noexcept` operator, we propose the following:
|
||||||
|
|
||||||
|
- An evaluation of `noexcept( someFalseStaticNoexceptFunction )` will evaluate as `true`.
|
||||||
|
- An evaluation of `static noexcept( someFalseStaticNoexceptFunction )` will evaluate as `true`.
|
||||||
|
- An evaluation of `false static noexcept( someClassicNoexceptFunction )` will evaluate as `false`.
|
||||||
|
- An evaluation of `false static noexcept( someStaticNoexceptFunction )` will evaluate as `false`.
|
||||||
|
- An evaluation of `false static noexcept( someFalseStaticNoexceptFunction )` will evaluate as `true`.
|
||||||
|
- A call to a `false static noexcept( true )` function will not throw.
|
||||||
|
- If an exception unwind (somehow) attempts to "emerge" from a
|
||||||
|
`false static noexcept( true )` function, then the program will terminate.
|
||||||
|
|
||||||
|
However, we propose to add the following behaviors and restrictions to such functions:
|
||||||
|
|
||||||
|
- If a `false static noexcept( false )` function is called outside of the body of a `try` block,
|
||||||
|
then the program is ill formed, and a compile-time diagnostic is required.
|
||||||
|
- If a `false static noexcept( false )` function is called inside the body of a `try` block, then
|
||||||
|
a `catch( ... )` block must exist.
|
||||||
|
- A `catch` block's body is not considered part of a `try` block.
|
||||||
|
- When checking if a statement is "in" a `try` block, one must walk up the nested
|
||||||
|
block structure until a try block is reached. A `catch` block attached to a
|
||||||
|
`try` block which is inside of a try block at broader scope is considered to be
|
||||||
|
"inside" the broader try block, for the purpose of these rules.
|
||||||
|
- A simple model of this is that invoking `false static noexcept( false )` functions is ill formed
|
||||||
|
unless a `try` block scope can be found by walking outward from the calling scope.
|
||||||
|
- It is unclear at this time if language UB on expressions should be considered
|
||||||
|
throwing or not. There are tradeoffs.
|
||||||
|
- If UB is considered `noexcept( true )`, then there is a potential that UB
|
||||||
|
can cause program termination by "leaking" an exception out from checked
|
||||||
|
try blocks.
|
||||||
|
- If UB is considered `noexcept( false )`, then it makes writing
|
||||||
|
`static noexcept( true )` extremely difficult. Many situations will
|
||||||
|
require noisy and defensive
|
||||||
|
`try { /* code */ } catch( ... ) { /* silently ignore exception and do nothing */ }`
|
||||||
|
patterns.
|
||||||
|
|
||||||
|
The conclusion about whether language UB should be considered `false static noexcept( true )`
|
||||||
|
for the purpose of this checking is irrelevant, as this form exists merely for expository
|
||||||
|
purposes.
|
||||||
|
|
||||||
|
#### Rewriting the original painful example using this feature
|
||||||
|
|
||||||
|
~~~
|
||||||
|
void silentlyThrowing() noexcept( false ) { throw 0; }
|
||||||
|
void wrappedSilentlyThrowing() noexcept( true ) { silentlyThrowing(); }
|
||||||
|
|
||||||
|
// We try to be more responsible
|
||||||
|
void
|
||||||
|
tickingTimeBomb() false static noexcept( true )
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if( not ( rand() % 32 ) )
|
||||||
|
{
|
||||||
|
silentlyThrowing();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( not ( rand() % 32 ) )
|
||||||
|
{
|
||||||
|
wrappedSilentlyThrowing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Result { Success, Failure };
|
||||||
|
|
||||||
|
Result
|
||||||
|
illFormedCannotTolerateExceptions() false static noexcept( true )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto element= someVector.at( 42 );
|
||||||
|
|
||||||
|
someVector.push_back( std::move( element ) );
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::cerr << "Something went wrong" << std::endl;
|
||||||
|
}
|
||||||
|
catch( ... ) { /* Failure to log is troublesome but not fatal */ }
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This line is ill formed and has to be moved into the try block to satisfy the `false static noexcept`
|
||||||
|
// requirements
|
||||||
|
tickingTimeBomb();
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result
|
||||||
|
cannotTolerateExceptions() false static noexcept( true )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto element= someVector.at( 42 );
|
||||||
|
|
||||||
|
someVector.push_back( std::move( element ) );
|
||||||
|
|
||||||
|
tickingTimeBomb();
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::cerr << "Something went wrong" << std::endl;
|
||||||
|
}
|
||||||
|
catch( ... ) { /* Failure to log is troublesome but not fatal */ }
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
=-=-=-=-=-=-=-=-=-=-
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# `double static noexcept` -- a mechanism for static checking of noexcept blocks
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. Abstract
|
||||||
|
2. Discussion
|
||||||
|
3. Proposal
|
||||||
|
3. Examples
|
||||||
|
|
||||||
|
## Abstract
|
||||||
|
|
||||||
|
In C++, `noexcept` exists to indicate that a function does not throw an exception. However,
|
||||||
|
what it actually provides is that a function cannot possibly throw an exception. This is
|
||||||
|
enforced by "violence", if necessary -- the program will terminate rather than allow
|
||||||
|
an exception to pass a `noexcept` boundary. Unfortunately, this turns `noexcept` into a
|
||||||
|
ticking timebomb; any `noexcept( true )` function may unexpectedly call `std::terminate`
|
||||||
|
at any time, thus aborting a program. This may be undesirable in many different contexts,
|
||||||
|
from Functional Safety to Program Correctness to Contractual Guarantees. This proposal
|
||||||
|
provides a mechanism which permits various levels of static guarantees.
|
||||||
|
|
||||||
|
## Discussion
|
||||||
|
|
||||||
|
The `noexcept` facility was added to permit a language level (and type-system level)
|
||||||
|
facility for promising that a function does not throw and for checking it. However, the
|
||||||
|
enforcement of this promise is a purely runtime concern. This leads to troublesome
|
||||||
|
timebombs, such as this code.
|
||||||
|
|
||||||
|
~~~
|
||||||
|
void silentlyThrowing() noexcept( false ) { throw 0; }
|
||||||
|
|
||||||
|
void
|
||||||
|
tickingTimeBomb() noexcept( true )
|
||||||
|
{
|
||||||
|
if( not ( rand() % 32 ) )
|
||||||
|
{
|
||||||
|
silentlyThrowing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Result { Success, Failure };
|
||||||
|
|
||||||
|
Result
|
||||||
|
cannotTolerateExceptions() noexcept( true )
|
||||||
|
{
|
||||||
|
std::string element;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
element= someVector.at( 42 );
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::cerr << "Something went wrong" << std::endl;
|
||||||
|
}
|
||||||
|
catch( ... ) { /* Failure to log is troublesome but not fatal */ }
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
someVector.push_back( std::move( element ) );
|
||||||
|
tickingTimeBomb();
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
While some of the code and functions called in `cannotTolerateExceptions` is capable of
|
||||||
|
throwing, the caller attempts to resolve exceptions and handle them without program
|
||||||
|
termination. However, the `tickingTimeBomb` function is a hidden hazard. While
|
||||||
|
it declares itself to not throw exceptions (which is true), the exceptions thrown
|
||||||
|
by code it calls are not checked and will "bump into" the `noexcept( true )`
|
||||||
|
on `tickingTimeBomb`. As such, the program will terminate, despite the best efforts
|
||||||
|
of the `cannotTolerateExceptions()` implementation. The language requires a mechanism
|
||||||
|
to statically check whether callees are equally "responsible" about termination
|
||||||
|
semantics as the caller.
|
||||||
|
|
||||||
|
To this end, we propose three new mechanisms.
|
||||||
|
|
||||||
|
## Proposal
|
||||||
|
|
||||||
|
We propose a few "extensions" to the `noexcept` keyword used on function declarators.
|
||||||
|
We will outline these here.
|
||||||
|
|
||||||
|
##### Note about keyword bikeshedding
|
||||||
|
|
||||||
|
This paper proposes "compound" keywords by recycling the meaning of existing keywords.
|
||||||
|
The actual keyword or keyword sequences to define these kinds of `noexcept` function are
|
||||||
|
immaterial to the mechanics of this proposal and thus we defer the decision of keywords
|
||||||
|
at this time.
|
||||||
|
|
||||||
|
### A statically checked `noexcept` function - `static noexcept( true )`
|
||||||
|
|
||||||
|
We propose the introduction of `static noexcept` as both a function declaration
|
||||||
|
"decorator" and an operator. `static noexcept( true )` or `static noexcept`
|
||||||
|
tagged functions have similar semantics to `noexcept` tagged or colored functions:
|
||||||
|
|
||||||
|
- An evaluation of `noexcept( someStaticNoexceptFunction )` will evaluate as `true`.
|
||||||
|
- An evaluation of `static noexcept( someStaticNoexceptFunction )` will evaluate as `true`.
|
||||||
|
- An evaluation of `static noexcept( someClassicNoexceptFunction )` will evaluate as `false`.
|
||||||
|
- A call to a `static noexcept( true )` function will not throw.
|
||||||
|
- If an exception unwind (somehow) attempts to "emerge" from a
|
||||||
|
`static noexcept( true )` function, then the program will terminate.
|
||||||
|
|
||||||
|
However, we propose to add the following behaviors and restrictions to such functions:
|
||||||
|
|
||||||
|
- If a `noexcept( false )` function is called outside of the body of a `try` block,
|
||||||
|
then the program is ill formed, and a compile-time diagnostic is required.
|
||||||
|
- If a `noexcept( false )` function is called inside the body of a `try` block, then
|
||||||
|
a `catch( ... )` block must exist.
|
||||||
|
- A `catch` block's body is not considered part of a `try` block.
|
||||||
|
- When checking if a statement is "in" a `try` block, one must walk up the nested
|
||||||
|
block structure until a try block is reached. A `catch` block attached to a
|
||||||
|
`try` block which is inside of a try block at broader scope is considered to be
|
||||||
|
"inside" the broader try block, for the purpose of these rules.
|
||||||
|
- A simple model of this is that invoking `noexcept( false )` functions is ill formed
|
||||||
|
unless a `try` block scope can be found by walking outward from the calling scope.
|
||||||
|
- It is unclear at this time if language UB on expressions should be considered
|
||||||
|
throwing or not. There are tradeoffs.
|
||||||
|
- If UB is considered `false static noexcept( true )`, then there is a potential that UB
|
||||||
|
can cause program termination by "leaking" an exception out from checked
|
||||||
|
try blocks.
|
||||||
|
- If UB is considered `false static noexcept( false )`, then it makes writing
|
||||||
|
`false static noexcept( true )` extremely difficult. Many situations will
|
||||||
|
require noisy and defensive
|
||||||
|
`try { /* code */ } catch( ... ) { /* silently ignore exception and do nothing */ }`
|
||||||
|
patterns.
|
||||||
|
|
||||||
|
The conclusion about whether language UB should be considered `false static noexcept( true )`
|
||||||
|
for the purpose of this checking is irrelevant, as this form exists merely for expository
|
||||||
|
purposes.
|
||||||
|
|
||||||
|
#### Rewriting the original painful example using this feature
|
||||||
|
|
||||||
|
~~~
|
||||||
|
void silentlyThrowing() noexcept( false ) { throw 0; }
|
||||||
|
void wrappedSilentlyThrowing() noexcept( true ) { silentlyThrowing(); }
|
||||||
|
|
||||||
|
// We try to be more responsible
|
||||||
|
void
|
||||||
|
tickingTimeBomb() static noexcept( true )
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if( not ( rand() % 32 ) )
|
||||||
|
{
|
||||||
|
silentlyThrowing();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( not ( rand() % 32 ) )
|
||||||
|
{
|
||||||
|
wrappedSilentlyThrowing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Result { Success, Failure };
|
||||||
|
|
||||||
|
Result
|
||||||
|
illFormedCannotTolerateExceptions() false static noexcept( true )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto element= someVector.at( 42 );
|
||||||
|
|
||||||
|
someVector.push_back( std::move( element ) );
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::cerr << "Something went wrong" << std::endl;
|
||||||
|
}
|
||||||
|
catch( ... ) { /* Failure to log is troublesome but not fatal */ }
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This line is ill formed and has to be moved into the try block to satisfy the `false static noexcept`
|
||||||
|
// requirements
|
||||||
|
tickingTimeBomb();
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result
|
||||||
|
cannotTolerateExceptions() false static noexcept( true )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto element= someVector.at( 42 );
|
||||||
|
|
||||||
|
someVector.push_back( std::move( element ) );
|
||||||
|
|
||||||
|
tickingTimeBomb();
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::cerr << "Something went wrong" << std::endl;
|
||||||
|
}
|
||||||
|
catch( ... ) { /* Failure to log is troublesome but not fatal */ }
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
~~~
|
||||||
Reference in New Issue
Block a user