Following code is about exception handling. I got the output:
Botch::f()
I'll be back!
Why Fruit is not caught? Thanks!
Ignore this. I think I have provided enough detail.
#include <exception>
#include <iostream>
using namespace std;
void terminator() {
cout << "I'll be back!" << endl;
exit(0);
}
void (*old_terminate)() = set_terminate(terminator);
class Fruit {};
class Botch {
public:
void f() throw(Fruit, bad_exception) {
cout << "Botch::f()" << endl;
throw Fruit();
}
~Botch() { throw 'c'; }
};
int main() {
try{
Botch b;
b.f();
} catch(Fruit&) {
cout << "inside catch(Fruit)" << endl;
} catch(bad_exception&) {
cout << "caught a bad_excpetionfrom f" << endl;
}
}
Because during stack unwinding for your Fruit exception you threw another exception (from the Botch destructor). So your terminator was called instead. This is why throwing exceptions from a destructor is a bad idea,
Fruit is not caught because the code never reaches that catch clause. In the try block in main, the call to b.f() throws an exception of type Fruit. In response, the code destroys the Botch object before entering the catch clause. The destructor of Botch throws another exception, and that triggers the call to terminate.
When b.f() is called in main, a Fruit is thrown. Then execution leaves the try block, and before any catch handler can catch that Fruit, b is destroyed and 'c' is thrown. Throwing a second exception while the Fruit is still active leads to termination, regardless of any catch handlers.
This is the reason why you never shall throw from destructors.
because the program flow is as follows:
try{
Botch b;
b.f();
//-> exception of class Fruit has been thrown
//-> Stack unwinding: during stack unwinding object b,
//which is on stack is destroyed, and its destructor is called
//-> this destructor ~Botch() { throw 'c'; } throws another exception
//and this caused call of your terminator()
} catch(Fruit&) { // so we are never here
Related
As far as I know, throwing an exception when another has not been handled yet is undefined behavior, and the program may crash. An exception is considered unhandled until it gets into the catch-block. I have the following code snippet:
#include <iostream>
using namespace std;
class ThrowingInDestructorClass
{
public:
ThrowingInDestructorClass() = default;
~ThrowingInDestructorClass() {
try {
throw std::runtime_error("2-nd exception. ");
}
catch(...)
{
std::cout << "Catched an error during Throwing class cleanup. " << std::endl;
};
}
};
void doSmth()
{
try {
ThrowingInDestructorClass throwing;
throw std::runtime_error("1-St exception. ");
}
catch(...)
{
std::cout << "Catched an error during doSmth. " << std::endl;
};
}
int main() {
doSmth();
}
Here we have a class that can throw and handle an exception inside its destructor, so it is OK. But we have a method that creates objects and throws an exception. During stack-unwinding, the class destructor will be called, throwing a 2-nd exception. So the 1-St exception will be unhandled yet.
When I run it, I get the following output:
Caught an error during Throwing class cleanup.
Caught an error during doSmth.
It may seem that everything is fine, but I'm not entirely sure that there is no UB here.
Could someone help to clarify the situation?
This answer is mostly just a summary of the comments:
I'll go through the program step by step starting at the point the first exception is thrown:
Stack unwinding begins by destroying the "throwing" object.
The destructor of the "throwing" object gets called, throwing another exception.
Stack unwinding finds a catch block for the new exception immediately, handling the exception. The destructor exits normally.
The stack unwinding finds the catch block for the first exception, handling it.
doSmth() exits normally
No function exited with an exception, thereby the condition
"...If any function that is called directly by the stack unwinding mechanism, after initialization of the exception object and before the start of the exception handler, exits with an exception, std::terminate is called. ..." en.cppreference.com/w/cpp/language/throw - Richard Critten
isn't met.
And even if you remove the try catch in the destructor, no UB will occur:
#include <iostream>
using namespace std;
class ThrowingInDestructorClass
{
public:
ThrowingInDestructorClass() = default;
~ThrowingInDestructorClass() {
throw std::runtime_error("2-nd exception. ");
}
};
void doSmth()
{
try {
ThrowingInDestructorClass throwing;
throw std::runtime_error("1-St exception. ");
}
catch(...)
{
std::cout << "Catched an error during doSmth. " << std::endl;
};
}
int main() {
doSmth();
}
This program will crash because std::terminate is called when stack unwinding (as now a function exits with an exception).
If you throw an exception when another has not been handled yet, and you let the second exception escape a destructor that was called in process of handling the first exception, then you get a well-defined program termination. –
n. 1.8e9-where's-my-share m.
Your program will crash, but that crash is not UB but well-defined behaviour
Consider this small snippet of code, which is actually part of a larger codebase:
class A
{
public:
A()
{
std::cout << "A" << std::endl;
}
~A()
{
std::cout << "~A" << std::endl;
}
};
void f()
{
A a;
throw;
}
void g()
{
try
{
f();
}
catch(...)
{
std::cout << "Caught" << std::endl;
}
}
For my particular case, the output turns out to be
A
~A
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
It seems that rather than the exception being caught, the program is just terminated. However, if I remove A's constructor, the exception does get caught.
Without closely analyzing the code, is it possible to know what causes this sort of behaviour?
A throw-expression with no operand, as in your code:
Rethrows the currently handled exception (the same object, not a copy of it)
Or, if there is no currently handled exception, calls std::terminate.
I am assuming f() is not being called while an exception is being handled (I imagine you're calling it directly from main or something). Thus, std::terminate is called.
The object a is irrelevant.
#include <iostream>
using namespace std;
class Cls
{
public:
~Cls()
{
throw "exp";
}
};
int main()
{
try
{
Cls c;
throw "exp";
}
catch (...)
{
cout << "Why this doesn't call" << endl;
}
}
When I execute this code, it doesn't goes in catch block. And give following exception,
But, when I run this code with little modification, it goes to catch block.
int main()
{
try
{
throw "exp";
throw "exp";
}
catch (...)
{
cout << "Why this doesn't call" << endl;
}
}
Output:
Both the above code throws 2 exception, then why Compiler is biased in destructor's case?
In the first case you first throw from the try block and then the stack unwinding throws from Cls's destructor. So you have two exceptions to be handled. C++ handles this situation by calling terminate.
Because of the peculiarity of throwing from destructors, C++11 defines that all destructors are noexcept by default. Then even if there is no other exception to be handled, the exception from a destructor will cause terminate to be called.
The second case is OK because as soon as you throw the first exception try block is left and the exception is handled in the catch block.
This isn't a question on whether it's safe to throw an exception from a destructor.
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.9 states:
"During stack unwinding, all the local objects in all those stack frames are destructed. If one of those destructors throws an exception (say it throws a Bar object), the C++ runtime system is in a no-win situation: should it ignore the Bar and end up in the } catch (Foo e) { where it was originally headed? Should it ignore the Foo and look for a } catch (Bar e) { handler? There is no good answer — either choice loses information."
IE: if during stack unwinding another exception is thrown, then the runtime system is in a no-win situation because the catch handler to 'look for' is ambiguous.
Is there an 'exception' to the above, when the exception that is thrown during stack unwinding itself is in a try/catch block? In this case there is no ambiguity:
#include <iostream>
using namespace std;
class Component
{
public:
~Component()
{
cout << "In component destructor" << endl;
try
{
throw 1;
}
catch (...)
{
cout << "Caught exception in component destructor" << endl;
}
}
};
class Container
{
public:
~Container()
{
cout << "In container destructor" << endl;
Component component;
}
}
;
int main()
{
try
{
Container cont;
throw 'a';
}
catch (...)
{
cout << "Caught main exception ok" << endl;
}
return 0;
}
The following implies it, but I was wondering if anyone knew of the relevant C++ standard sections.
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr155.htm
"If during stack unwinding a destructor throws an exception and that exception is not handled, the terminate() function is called. The following example demonstrates this:"
Your Component destructor is safe. The rule you're quoting only applies if the exception is thrown out of the destructor (i.e., to the destructor's caller.)
EDIT: Here's one relevant quote from the standard (emphasis added)
Note: If a destructor called during
stack unwinding exits with an
exception, std::terminate is called
(15.5.1).
Consider the following program
#include <iostream>
#include<cstdlib>
using namespace std;
class E {
public:
const char* error;
E(const char* arg) : error(arg) { }
};
void my_terminate() {
cout << "Call to my_terminate" << endl;
}
struct A {
A() { cout << "In constructor of A" << endl; }
~A(){
cout << "In destructor of A" << endl;
throw E("Exception thrown in ~A()");
}
};
struct B {
B() { cout << "In constructor of B" << endl; }
~B() { cout << "In destructor of B" << endl; }
};
int main() {
set_terminate(my_terminate);
try {
cout << "In try block" << endl;
A a;
B b;
throw E("Exception thrown in try block of main()"); // Line 36
}
catch (E& e) {
cout << "Exception: " << e.error << endl;
}
catch (...) {
cout << "Some exception caught in main()" << endl;
}
cout << "Resume execution of main()" << endl;
}
Output:
In try block
In constructor of A
In constructor of B
In destructor of B
In destructor of A
Call to my_terminate
Disallowed system call: SYS_kill
In line 36 an exception is thrown from the try block in main. Now why is this exception not caught by the handler?
Rather the 'stack unwinding' process continues.The destructor of A throws an exception too which is again not caught by any handler,instead a call to my_terminate is made, why?
Why is the handler not called in the two cases?
The C++ rule is that you must never throw an exception from a destructor that is being called during the "stack unwinding" process of another exception.
You throw an exception in A's destructor, which is something you are not supposed to do.
When you throw the original E temporary from the try block in main, the runtime implementation constructs an exception object of type E and searches for the first catch block that can handle the exception. In this case, this is the immediately following catch (E& e) block.
When the implementation finds the correct catch to handle the exception, it then destroys all automatic variables which must go out of scope by moving out of the scope where the throw occurred to the scope in which the catch resides.
In this case the objects a and b which are local to the catch block go out of scope, so must be destroyed (in the reverse order that they were created). However, destroying a causes another exception to be thrown. Because the implementation already has an uncaught exception and has already chosen a catch handler for that exception which it is trying to reach, there is no mechanism to handle this new exception. The rule in this case is that std::terminate, and in your case your terminate handler, is called immediately.
You should note that your my_terminate function is not a conforming terminate_handler, as a terminate_handler must not return and must terminate the program execution (i.e. must not throw either). Yours returns implicitly.
set_terminate
function installs term_func as the function called by terminate. set_terminate is used with C++ exception handling and may be called at any point in your program before the exception is thrown. terminate calls abort by default. You can change this default by writing your own termination function and calling set_terminate with the name of your function as its argument. terminate calls the last function given as an argument to set_terminate. After performing any desired cleanup tasks,
term_func should exit the program.
If it does not exit (if it returns to its caller), abort is called.
my_terminate() should look like :
void my_terminate()
{
cout << "Call to my_terminate" << endl;
*
*
*
exit(-1);
}
In section 15.2 of my draft standard it states:
3 The process of calling destructors
for automatic objects constructed on
the path from a try block to a
throw-expression is called “stack
unwinding.” [ Note: If a destructor
called during stack unwinding exits
with an exception, std::terminate is
called (15.5.1). So destructors should
generally catch exceptions and not let
them propagate out of the destructor.
—end note ]
They have defined "stack unwinding" broadly enough that it seems to cover this case, even if it is all happening within one function. I guess it's somewhat clear that implementations expect destructors not to try and propagate exceptions outward.
Here is the problem. Your A's destructor throws, which is a bad thing. Re-throwing exceptions, or throwing a new exception in an exception handler is kosher because the stack-unwinding is well-behaved. In that case, only one exception is alive at the current stack frame. When a destructor throws an exception during the stack unwinding process however, two exceptions are alive the same stack frame, i.e they unwind the stack on the same level. In your case, that's two E objects. So which one does one choose to follow? You cannot follow both, so the standard says that terminate() will be called. You can make the exception system use your custom terminate routine by passing one with std::set_terminate() from the header <exception>.
You seem to think that your std::terminate() handler can resume your program by returning, but that's undefined behavior.
If you absolutely positively need to throw from a destructor and can't contain it with an exception handler inside the destructor itself, here is a workaround:
The function uncaught_exception() from the header <exception> returns true if an exception has been thrown, but not yet caught. If it returns true, that means that the process is in the middle of a stack unwinding, unwinding the stack and calling destructors until it finds a proper exception handler. Use the function inside destructors which throw, so that they only throw when a stack unwinding is not happening.
Here's an example on how to use uncaught_exception() (Though, it's an extremely bad idea):
#include <iostream>
#include <exception>
#include <stdexcept>
#include <sstream>
#include <cstdlib>
void termhandler()
{
std::cout << "Inside terminate()" << std::endl;
abort();
}
class Foo
{
public:
Foo(int val) : i(val){ std::cout << "Created Foo object " << i << std::endl; }
~Foo()
{
if(std::uncaught_exception()){
std::cout << "~Foo::Foo() object " << i << " : " << "Stack unwinding in progress. Can't throw!" << std::endl;
} else {
std::cout << "~Foo::Foo() object " << i << " : " << "Throwing test exception." << std::endl;
std::ostringstream strm;
strm << i;
std::runtime_error e("Exception from ~Foo::Foo() object " + strm.str());
throw e;
}
}
int i;
};
int main()
{
try {
std::set_terminate(termhandler);
Foo A(1);
Foo B(2);
} catch(std::exception& e){
std::cout << "Caught exception in main() : " << e.what() << std::endl;
}
}
Which gives the following output:
Created Foo object 1
Created Foo object 2
~Foo::Foo() object 2 : Throwing test exception.
~Foo::Foo() object 1 : Stack unwinding in progress. Can't throw!
Caught exception in main() : Exception from ~Foo::Foo() object 2