removed remaining throw lists

This commit is contained in:
Frank B. Brokken 2021-12-03 09:18:06 +01:00
parent 77df8a59c5
commit ed300494ed
10 changed files with 34 additions and 202 deletions

View file

@ -3,10 +3,12 @@ Add content to section first: std::byte
Add weak_ptr
Mention namespace chrono_literals
std::option
std::iota
coroutines
std::ranges
std::jthread
rm annotations/OBS/ entries

View file

@ -1,2 +1,2 @@
#define VERSION "12.0.0-pre"
#define VERSION "12.0.0-isn"
#define YEARS "1994-2021"

View file

@ -1,3 +1,8 @@
C++-annotations (12.0.0-isn)
* throw(typelist) specifications were removed from the language, and the
section covering throw(typelist) was removed from the C++ Annotations.
C++-annotations (11.6.0)
* Added stl/optional.yo covering std::optional

View file

@ -89,7 +89,7 @@ not to use tt(noexcept) in your code:
merely means that if such a function throws an exception
tt(std::terminate) rather tha tt(std::unexpected) is called.
it() Functions previously provided with an empty throw list (tt(throw()))
should now be provided with tt(noexcept(true)).
should be provided with tt(noexcept).
it() tt(noexcept) specifications are required when using the following std
traits (declared in the tthi(type_traits) header file):
itemization(

View file

@ -86,7 +86,7 @@
}
return (*this);
}
Type &operator[](size_t index) throw(char const *)
Type &operator[](size_t index)
{
if (index > (finish - start))
throw "Vector array index out of bounds";

View file

@ -27,11 +27,8 @@ includefile(exceptions/catch)
subsect(The default catcher)
includefile(exceptions/defaultcatch)
sect(Declaring (deprecated) exception throwers)
includefile(exceptions/declaring)
subsect(noexcept)
includefile(exceptions/noexcept)
sect(Functions that cannot throw exceptions: the `noexcept' keyword)
includefile(exceptions/noexcept)
lsect(IOEXCEPTIONS)(Iostreams and exceptions)
includefile(exceptions/iostreams)

View file

@ -1,83 +0,0 @@
Once a function has been defined it's commonly called from other functions. If
called functions are not defined in the same source file as calling functions
the called functions must be declared, for which header files are commonly
used.
The called functions may throw exceptions. When such functions are declared
their declarations may specify a (now deprecated, see also section
ref(NOEXCEPT)) hi(throw list) emi(function throw list) or
emi(exception specification list) specifying the types of the exceptions
that can be thrown by the called function. For example, a function that may
throw `tt(char *)' and `tt(int)' exceptions can be declared as
verb( void exceptionThrower() throw(char *, int);)
Function throw lists immediately follow the function header (and their
specifications also follow possible tt(const) specifiers). Throw lists
specify zero or more, comma separated, types, using the following syntax:
verb( throw ()
throw (type)
throw (type1, type2, type3 ...))
where the ellipsis indicates any number of additional, comma separated,
type specifications.
To indicate that a function is guaranteed not to throw exceptions an
i(empty function throw list) can be used. E.g.,
verb( void noExceptions() throw ();)
In all cases, the function header used in the function definition must
exactly match the function header used in the declaration, including a
possibly empty function throw list.
Once a function throw list has been specified its function may only throw
exceptions of the types mentioned in its throw list. A emi(run-time error)
occurs if such a function throws exceptions of types not specified in its
function throw list. Example: the function tt(charPintThrower) shown below
clearly throws a tt(char const *) exception. Since, according to its function
throw list, tt(intThrower) may throw an tt(int) exception, the function throw
list of tt(charPintThrower) must em(also) contain tt(int).
verbinclude(-a examples/throwlist.cc)
A function without a throw list may throw any kind of exception. Without
a function throw list the program's designer is responsible for providing the
correct handlers.
For various reasons declaring exception throwers is now deprecated. Declaring
exception throwers does not imply that the em(compiler) checks whether an
improper exception is thrown. Rather, the function for which a function throw
list has been specified is surrounded by additional code in which the actually
thrown exception is inspected: if the exception is of a type that is listed in
the function's throw list then that exception is rethrown; otherwise a
run-time error is thrown. Instead of compile-time checks you get run-time
overhead, resulting in additional code (and execution time) that is added to
the function's code. One could write, e.g.,
verb( void fun() throw (int)
{
// code of this function, throwing exceptions
})
but the function would be compiled to something like this (cf.
section ref(FUNTRY) for the use of tt(try) immediately following the
function's header and section ref(STDEXC) for a description of
ti(bad_exception)):
verb( void fun()
try // this code resulting from throw(int)
{
// the function's code, throwing all kinds of exceptions
}
catch (int) // remaining code resulting from throw(int)
{
throw; // rethrow the exception, so it can be caught by the
// `intended' handler
}
catch (...) // catch any other exception
{
throw bad_exception{};
})
Run-time overhead results because the number of thrown and caught
exceptions are doubled. If no function throw list is specified then a thrown
tt(int) is simply caught by its intended handler; if a function throw list has
been specified the thrown tt(int) is em(first) caught by the `safeguarding'
handler added to the function. In there it is em(rethrown) whereafter it is
caught by its intended handler.

View file

@ -1,40 +0,0 @@
#include <iostream.h>
void intThrower() throw(int);
void charP_IntThrower() throw (char *, int);
void intThrower(int x) throw (int)
{
if (x)
throw x;
}
void charP_IntThrower() throw (char *, int)
{
int
x;
cout << "Enter an int: ";
cout.flush();
cin >> x;
intThrower(x);
throw "from charP_IntThrower() with love";
}
int main()
{
try
{
charP_IntThrower();
}
catch (char *message)
{
cout << "Text exception: " << message << '\n';
}
catch (int value)
{
cout << "Int exception: " << value << '\n';
}
return (0);
}

View file

@ -1,57 +0,0 @@
#include <iostream>
using namespace std;
void charPintThrower() throw(char const *, int);
class Thrower
{
public:
void intThrower(int) const throw(int);
};
void Thrower::intThrower(int x) const throw(int)
{
if (x)
throw x;
}
void charPintThrower() throw(char const *, int)
{
int x;
cerr << "Enter an int: ";
cin >> x;
Thrower().intThrower(x);
throw "this text is thrown if 0 was entered";
}
void runTimeError() throw(int)
{
throw 12.5;
}
int main()
{
try
{
charPintThrower();
}
catch (char const *message)
{
cerr << "Text exception: " << message << '\n';
}
catch (int value)
{
cerr << "Int exception: " << value << '\n';
}
try
{
cerr << "Generating a run-time error\n";
runTimeError();
}
catch(...)
{
cerr << "not reached\n";
}
}

View file

@ -1,16 +1,24 @@
Although function throw lists are deprecated, its younger cousin ti(noexcept)
is not. The tt(noexcept) keyword is used where previously empty function throw
lists were used (cf. section ref(SYSTEMERROR) for examples where tt(noexcept)
is used). Like empty function throw lists you incur some run-time overhead,
but tt(noexcept) is more strict than empty function throw lists when
violations are observed. When violating function throw list specifications a
tt(std::unexpected) exception is thrown, when violating tt(noexcept) it
results in tt(std::terminate), ending the program.
Once a function has been defined it's often called from other functions. If
called functions are not defined in the same source file as calling functions
the called functions must be declared, for which header files are often
used. Those called functions might throw exceptions, which might be
unacceptible to the function calling those other functions. E.g., functions
like tt(swap) and destructors may not throw exceptions.
In addition, tt(noexcept) can be given an argument that is evaluated
compile-time: if the evaluation returns tt(true) then the tt(noexcept)
requirement is used; if the evaluation returns tt(false), then the
tt(noexcept) requirement is ignored. Examples of this advanced use of
Functions that may not throw exceptions can be declared and defined by
specifying the ti(noexcept) keyword (see section ref(SYSTEMERROR) for examples
of function declarations specifying tt(noexcept)).
When using tt(noecept) there's a slight run-time overhead penalty because the
function needs an over-all tt(try-catch) block catching any eception that
might be thrown by its (called) code. When an exception is caught (violating
the tt(noexcept) specification) then the tt(catch) clause calls
tt(std::terminate), ending the program.
In addition to using a plain tt(noexcept), it can also be given an argument
that is evaluated compile-time: if the evaluation returns tt(true) then the
tt(noexcept) requirement is used; if the evaluation returns tt(false), then
the tt(noexcept) requirement is ignored. Examples of this advanced use of
tt(noexcept) are provided in section ref(NOEXCEPT).