I have 2 questions about non-throwing functions:
Why make a function non-throwing?
How to make a function non-throwing? If the code inside the function actually may throw
, then should I still make it non-throwing?
Here is an example:
void swap(Type t1, Type t2) throw()
{
//swap
}
If the code in swap
won't throw at all, should I still append throw()
? Why?
If you throw, your program terminates What happens if you throw from a noexcept function? Your program terminates, and may or may not unwind the stack. Terminating program isn't the nicest way to report an error to your user. You would be surprised that most of C++ code might throw.
There are two good reasons for the use of noexcept: First, an exception specifier documents the behaviour of the function. If a function is specified as noexcept, it can be safely used in a non-throwing function. Second, it is an optimisation opportunity for the compiler.
The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions. It can be used within a function template's noexcept specifier to declare that the function will throw exceptions for some types but not others.
Exception specifications are a C++ language feature that indicate the programmer's intent about the exception types that can be propagated by a function. You can specify that a function may or may not exit by an exception by using an exception specification.
throw()
(or noexcept
in C++11) is useful for two reasons:
Non-throwing functions are very important for writing exception safe code. For instance, the usual way of writing an exception safe operator=
is via a non-throwing swap()
function.
On the other hand, other exception specifications are useless and have been justly deprecated in the current standard. They don't mix well at all with templates and are too expensive to enforce.
Now, if you use a noexcept
specification in a function that might actually throw, all bets are off. Even if your compiler does not terminate the program when an exception leaves the function (VS does not do it for runtime efficiency reasons, for instance), your code might not do what you thought because of optimisations. For example:
void f() noexcept
{
a();
b();
}
If a()
actually throws and b()
has side effects, the function behaviour will be unpredictable, because your compiler may decide to execute b()
before a()
, since you have told it that no exceptions will be thrown.
EDIT: Now for the second part of your question: how to make a function non-throwing?
First you need to ask yourself whether your function should really be non-throwing. For instance:
class C
{
C* CreateInstance()
{
return new C();
}
}
Since operator new
can throw a std::bad_alloc
, CreateInstance()
can throw. You could try to avoid it with a try-catch block, handling or swallowing any exceptions that may be thrown inside the try
block, but would that really be sensible? For instance:
C* CreateInstance()
{
try
{
return new C();
}
catch (...)
{
return null;
}
}
Problem solved, it seems, but would your callers be prepared for CreateInstance()
returning null
? If not, a crash will ensue when they try to use that pointer. Besides, a std::bad_alloc
usually means that you have run out of memory and you would just be postponing the problem.
So be careful: some functions can be made non-throwing, but others should be allowed to throw. Exception safety is not a trivial matter.
Why make a function non-throwing?
So callers of the function can call it without having to take any actions to deal with exceptions being raised by the function.
How to make a function non-throwing? If the code inside the function actually may throw, then should I still make it non-throwing?
You can make the code non-throwing by putting all code which could throw the inside a try block, and deal with any exceptions without re-throwing.
void swap(T t1, T t2) noexcept {
try {
// ....
} catch (const std::exception& ex) {
// ....
} catch (...) {
// ....
}
}
If you claim your function doesn't throw, then you have to make it non-throwing. But this doesn't mean adding an exception specification, which you shouldn't do anyway, since it is deprecated. It means you must ensure the function doesn't throw, no matter what. The C++11 keyword noexcept
gives you some compile-time safety in this respect.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With