The code in question is this:
struct something_bad_happened_exception : std::exception {};
void foo() {
something_bad_happened_exception e;
throw e;
}
clang gives a warning that reads:
Throw expression should throw anonymous temporary values instead [cert-err09-cpp]
which means foo()
should be changed to:
void foo() {
throw something_bad_happened_exception();
}
Why is it better to throw a temporary instead of a local variable?
According to the cpp reference on a throw expression:
First, copy-initializes the exception object from expression (this may call the move constructor for rvalue expression, and the copy/move may be subject to copy elision)
Thus, your code if perfectly fine, but a copy constructor will be called, which may be undesirable in terms of efficiency. Still, copy elision may occur if (emphasis mine)
Under the following circumstances, the compilers are permitted, but not required to omit the copy
[omissis]
In a throw-expression, when the operand is the name of a non-volatile object with automatic storage duration, which isn't a function parameter or a catch clause parameter, and whose scope does not extend past the innermost try-block (if there is a try-block).
As an example, consider the following code
#include <exception>
#include <iostream>
struct something_bad_happened_exception : std::exception {
something_bad_happened_exception(const something_bad_happened_exception& r) {
std::cout << "A copy has occoured!" << std::endl;
}
something_bad_happened_exception() { }
};
int main()
{
std::cout << "First throw" << std::endl;
try {
const something_bad_happened_exception e;
throw e;
}
catch (const std::exception& ex)
{
std::cout << "Caught exception" << std::endl;
}
std::cout << "Second throw" << std::endl;
try {
throw something_bad_happened_exception();
}
catch (const std::exception& ex)
{
std::cout << "Caught exception" << std::endl;
}
return 0;
}
Compiling the code with gcc 8.2.1
and clang 6.0
, with option -O3
the output is
First throw
A copy has occoured!
Caught exception
Second throw
Caught exception
The first throw
corresponds to your example. Even if a copy of e
could be omitted, neither gcc
nor clang
implement copy elision.
The second throw
has an anonymous temporary, and no copy occurs.
The code doesn't conform to the convention of "throw only anonymous temporaries" (note the option CheckThrowTemporaries
), which is what the style checker inspects.
That convention, and this inspection are overly strict as far "throw by value" convention is concerned - in that regard the example program is conforming. A truly non conforming example would be throwing a pointer to an object.
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