Given this code:
struct A {
A(int e) { throw e; }
};
struct B {
A a{42}; // Same with = 42; syntax
};
int main() {
try {
B b;
} catch (int const e) {
return e;
}
}
When compiled with GCC (versions 4.7.4, 4.8.5, 4.9.3, 5.4.0, 6.3.0):
$ g++ -std=c++11 test.cpp -o test; ./test ; echo $?
terminate called after throwing an instance of 'int'
Aborted
134
But when compiled with Clang (version 4.0.0):
$ clang++ -std=c++11 test.cpp -o test; ./test ; echo $?
42
Which behavior is correct?
This is a bug in GCC (Bug 80683).
If the constructor is the first op in the try/catch
clause, then the compiler considered it as being outside of it although it should include it.
For example, the following works just fine:
#include <iostream>
struct A {
A(int e) { throw e; }
};
struct B {
A a{42}; // Same with = 42; syntax
};
int main() {
try {
// The following forces the compiler to put B's contructor inside the try/catch.
std::cout << "Welcome" << std::endl;
B b;
} catch (int e) {
std::cout << "ERROR: " << e << std::endl; // This is just for debugging
}
return 0;
}
Running:
g++ -std=c++11 test.cpp -DNDEBUG -o test; ./test ; echo $?
Outputs:
Welcome
ERROR: 42
0
My guess is that is that due to compiler optimization, it moves the constructor to the beginning of the main function. It assumes that the struct B
has no constructor, then it assumes that it would never throw an exception, thus it is safe to move it outside of the try/catch
clause.
If we will change the declaration of struct B
to explicitly use struct A
constructor:
struct B {
B():a(42) {}
A a;
};
Then the result will be as expected and we will enter the try/catch
, even when removing the "Welcome" printout:
ERROR: 42
0
Clang is correct. References about that can be found in C++ standard reference draft n4296 (emphasize mine):
15.3 Handling an exception [except.handle]
...
3 A handler is a match for an exception object of type E if
(3.1) — The handler is of type cv T or cv T& and E and T are the same type (ignoring the top-level cv-qualifiers),
Here an int
is thrown, and the handler declares a const int
. There is a match and the handler shall be invoked.
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