I am interested whether this is forced by standard and whether it is violated by some compiler. My observation is that:
gcc (6.3.0), stack in throw() function is unwound but then std::terminate is called (exception cannot be cought by try/catch). But with 7.0 (current HEAD), no stack is being unwound, std::termiante is called immediately. Actually gcc 7.0 even warns of this : warning: throw will always call terminate() [-Wterminate]
for NoExceptFunctionWithObj2()
. It makes throw() behave as noexcept(true).
clang, in all versions I have checked unwinds function stack (objects d-tors are called), and then std::terminate is called.
#include <iostream>
#include <string>
#include <vector>
struct TestDataWithoutNoexcept {
TestDataWithoutNoexcept() {
std::cout << __FUNCTION__ << "\n";
}
~TestDataWithoutNoexcept() {
std::cout << __FUNCTION__ << "\n";
}
TestDataWithoutNoexcept(TestDataWithoutNoexcept const & rhs) {
std::cout << __FUNCTION__ << "\n";
}
TestDataWithoutNoexcept(TestDataWithoutNoexcept && rhs) {
std::cout << __FUNCTION__ << "\n";
}
TestDataWithoutNoexcept& operator=(TestDataWithoutNoexcept const& rhs) {
std::cout << __FUNCTION__ << "\n";
}
};
void NoExceptFunctionWithObj1() noexcept {
TestDataWithoutNoexcept test;
throw std::runtime_error("NoExceptFunctionWithObj1 ex.");
}
void NoExceptFunctionWithObj2() throw() {
TestDataWithoutNoexcept test;
throw std::runtime_error("NoExceptFunctionWithObj2 ex.");
}
int main()
{
// Now lets see whether stack is being unwound when exception is thrown in noexcept versus throw() function.
std::cout << "\n See how dtors are called in noexcept or throw() functions\n";
try {
//NoExceptFunctionWithObj1();
}
catch (std::runtime_error& ex) {
std::cout << ex.what();
}
try {
NoExceptFunctionWithObj2();
}
catch (std::runtime_error& ex) {
std::cout << "\nShouldn't this be shown? : " << ex.what();
}
}
Yes, std::terminate
should be called. The latest published draft of the standard says :
15.4 [except.spec], paragraph 12
An exception-specification is non-throwing if it is of the form throw() , noexcept , or noexcept( constant-expression ) where the constant- expression yields true .
Which means that throw()
is strictly equivalent to noexcept(true)
. throw()
is deprecated in C++17
.
15.5.1 [except.terminate]
when the search for a handler (15.3) encounters the outermost block of a function with a noexcept- specification that does not allow the exception (15.4) [...] std::terminate() is called (18.8.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called
Not calling std::terminate
means MSVC is not compliant.
Regarding the handling of the stack, the compiler does what it wants about unwinding it or not in your example — this is specified to be implementation-defined .
Historically (before C++11) stack unwinding in this situation was mandatory. However it turned out that the runtime cost of this enforced behaviour was too high and it was inhibiting the compiler to do some optimizations (even in the non-exception case). As a result, the compiler is now free to leave this out.
Edited after clarifications from @mike.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.