I meant to get some knowledge of stack unwinding and came across this page,which demonstrates it with the example below.
#include <iostream>
using namespace std;
struct E {
const char* message;
E(const char* arg) : message(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("Exception thrown in try block of main()");
}
catch (const char* e) {
cout << "Exception: " << e << endl;
}
catch (...) {
cout << "Some exception caught in main()" << endl;
}
cout << "Resume execution of main()" << endl;
}
However it got core dumped when I compiled with g++/*clang++*.The output is as follows:
In try block
In constructor of A
In constructor of B
In destructor of B
In destructor of A
Call to my_terminate
已放弃 (核心已转储) #core dump
Can anyone give me some hints?
The answer is that you are throwing an exception while you are throwing an exception.
In main(), you construct an A instance. You then throw an exception. Before it is caught, A::~A is called, which also throws an exception. Having two exceptions in flight at the same time causes terminate() (or the user supplied equivalent) to be called (which, by default, calls abort(), which drops a core. Either way, the program cannot recover.)
Aside: this is what leads to the general best practice rule where you must not throw exceptions in destructors unless you mean for it to kill your program.
set_terminate() expects the function providide to it terminate the program.
Function that takes no parameters and returns void. The function shall
not return and shall terminate the program. terminate_handler is a
function pointer type taking no parameters and returning void.
set_terminate automatically calls abort() after calling your terminate function if you don't exit in the function provided.
Simply add exit(0); in my_terminate() to avoid seeing this abort() message.
Related
I understand that exception handler catch(...) in C++ handles any type of exception. I am wondering what happens if it has to handle an exception that is of some class type - is the object of that class passed to this handler by reference or by value?
This is the code that could help in understanding this. When the exception of type B is thrown in "Inner try", an unnamed temporary object of class B is created with the default constructor of class B. When I run this program, copy constructor of class B doesn't get called at all, and this unnamed temporary object of class B is destroyed only after executing "Outer try 3", which means that object was propagated backwards all the way to the "Outer try 3". So my guess is that objects are passed by reference to the catch(...) handler, but I wanted to see if this is correct reasoning.
#include <iostream>
using namespace std;
class A {
public:
A() {
cout << "Default constructor of class A" << endl;
}
A(const A& a) {
cout << "Copy constructor of class A" << endl;
}
A(A&& a) noexcept {
cout << "Move constructor of class A" << endl;
}
~A() {
cout << "Destructor of class A" << endl;
}
};
class B {
public:
B() {
cout << "Default constructor of class B" << endl;
}
B(const B& b) {
cout << "Copy constructor of class B" << endl;
}
B(B&& b) noexcept {
cout << "Move constructor of class B" << endl;
}
~B() {
cout << "Destructor of class B" << endl;
}
};
int main() {
try {
try {
try {
try {
throw A();
}
catch (A a) {
cout << "Inner try" << endl;
throw B();
}
}
catch (...) {
cout << "Outer try 1" << endl;
throw;
}
}
catch (...) {
cout << "Outer try 2" << endl;
throw;
}
}
catch (...) {
cout << "Outer try 3" << endl;
}
}
When you throw an exception, the exception object is created from the operand to throw. It is an object stored in an unspecified way.
When a matching handler for the exception is reached and the handler is not ..., then the handler's parameter is initialized from the exception object.
Essentially, if you declare a catch parameter as a non-reference type, you are getting a copy of the exception object (or of a base class subobject) in the handler. This is what you see in the A handler and why there is a call to the copy constructor. The copy lives until the handler exits. If you declare the parameter a reference type, then you will get a reference to the exception object and it will always refer to the same object if you rethrow the exception.
Rethrowing with throw; does not actually do anything with the parameter of the catch clause. It simply causes the exception handling to continue searching the catch clauses and stack unwinding. The exception object is still the same.
Nothing about this changes if the handler is catch(...). There is no variable (reference or not) to initialize in the handler, but throw; will rethrow and continue the search for a handler with the same exception object.
When a handler exits without rethrowing the exception, then the exception object is destroyed. This happens at the end of your outer-most catch for the B exception object and at the end of the inner-most catch for the A exception object. (You get two destructor calls to A, one for the catch parameter and one for the exception object.)
Consider the following C++ classes inheritance hierarchy and their intended polymorphic behaviour.
#include <iostream>
using namespace std;
class A
{
public:
A () { cout << "A constructor\n"; }
virtual void display() { cout << "A display\n"; }
virtual ~A() { cout << "A destructor\n"; }
friend ostream& operator << (ostream &out, A &a) {
a.display();
return out;
}
};
class B : public A
{
public:
B () { cout << "B constructor\n"; }
virtual void display() { cout << "B display\n"; }
virtual ~B() { cout << "B destructor\n"; }
};
class C : public B
{
public:
C () { cout << "C constructor\n"; }
virtual void display() {cout << "C display\n";}
virtual ~C() { cout << "C destructor\n"; }
};
int main()
{
C c1;
cout << endl; c1.display(); cout << endl;
c1.~C();
cout << endl; c1.display(); cout << endl;
c1.~C();
cout << "=================================================" << endl;
C c2;
cout << endl << c2 << endl;
c2.~C();
cout << endl << c2 << endl;
c2.~C();
return 0;
}
My understanding is that the display member function is virtual and therefore will always behave as such. In the top part of the main program it behaves well; that is when we call c1.display() it prints "C display" message. This is true even after destructing the c1 object.
In the lower part, we don't call the display function. Instead we call the output stream friend function which will in turn call the display member function. In this case, it works perfectly well at first; that is cout << endl << c2 << endl; prints C display. This is expected because we are passing the c1 object to the ostream friend function by reference and therefore late binding will take care of which display member function to execute.
But then when we do the same cout << endl << c2 << endl; after destructing c2 object, strangely the display member function is no more behaving as expected. It calls the base class display and prints "A display" message.
I don't understand it? Does destructing objects stop the late binding?
Destroying an object makes it illegal to continue calling member functions of that object. Your code's behaviour is undefined, and whatever behaviour you are observing cannot be relied upon to persist across even runs of the same program, let alone different compiler flags or entirely different implementations.
However, we can guess why you are seeing the particular behaviour you report, with the understanding that we should not continue to compile and run such code in the future as its behaviour is not guaranteed.
It is likely that your compiler is devirtualizing the c1.display() call since it can see the definition of c1 (and thus knows that its dynamic type is C). Thus, the generated code likely does not consult the vtable at all. This explains why you continue to see "C display" even though the object has already been destroyed.
In the c2 case, the object is being passed by reference and the compiler is probably not inlining aggressively enough to devirtualize the eventual display call. If it consults the vtable after c2 is destroyed, it probably finds the vtable for A, because the destruction process of the C object must eventually reset the A subobject's vptr to point to the A vtable prior to the execution of A::~A (in case A::~A calls any virtual functions). So that explains the "A display" message.
I'm trying to understand why throwing an exception from a destructor results in a program crash.
As I found many examples of two object which throw multiple exception and compiler can't handle multiple exception but in my case I only have a single exception thrown from the destructor. Why is my program still crashing?
class MyClass {
private:
string name;
public:
MyClass (string s) :name(s) {
cout << "constructor " << name << endl;
}
~MyClass() {
cout << "Destroying " << name << endl;
throw "invalid";
}
};
int main( )
{
try {
MyClass mainObj("M");
}
catch (const char *e) {
cout << "exception: " << e << endl;
cout << "Mission impossible!\n";
}
catch (...) {
cout << "exception: " << endl;
}
return 0;
}
Explanation from the MingW g++ compiler:
[P:\temp]
> g++ foo.cpp
foo.cpp: In destructor 'MyClass::~MyClass()':
foo.cpp:14:15: warning: throw will always call terminate() [-Wterminate]
throw "invalid";
^~~~~~~~~
foo.cpp:14:15: note: in C++11 destructors default to noexcept
To really let it throw you can do this:
~MyClass() noexcept(false){
Since C++11 destructors are implicitly declared as noexcept documentation
non-throwing functions are all others (those with noexcept specifier whose expression evaluates to true as well as destructors, defaulted special member functions, and deallocation functions)
emphasis is mine.
Below code exits by giving error
"abort() has been called".
Is it due to destructor throwing exception? I know throwing exception from destructor results in undefined behavior but there are counter arguments also. and moreover the same program works correct in VS 2012.
#include "stdafx.h"
#include<iostream>
using namespace std;
class Txn
{
public:
Txn()
{
cout<< "in Constructor" << endl;
};
~Txn()
{
try
{
cout << "in destructor" << endl;
throw 10;
}
catch(int i)
{
cout << "in destructor exception" << endl;
throw;
}
}
};
int main()
{
try
{
Txn t;
}
catch (int i)
{
cout << "Exception" << i << endl;
}
return 0;
}
VS2017 release notes does not mention anything around exception handling changes.
So i have below questions:
Is it incorrect to throw exception in destructor from VS2017 onwards? will it always exit the program by calling abort()?
Are there any flags with which we can make it work?
Please suggest.
The issue here is all destructors by default are noexcept(true). Throwing an exception without changing the will call std::terminate immediately. If we use
class Txn
{
public:
Txn()
{
cout<< "in Constructor" << endl;
};
~Txn() noexcept(false)
{
try
{
cout << "in destructor" << endl;
throw 10;
}
catch(int i)
{
cout << "in destructor exception" << endl;
throw;
}
}
};
int main()
{
try
{
Txn t;
}
catch (int i)
{
cout << "Exception" << i << endl;
}
return 0;
}
The program runs as expected.
The reason this worked in VS2012 but not VS2017 is before C++11 a destructor could throw without you needing to specify it. With C++11 noexcept specifiers and the change that all destructors are noexcept by default causes it to break in VS2017.
Destructors are by default expected to not throw exceptions (noexcept). You can tell the compiler that this destructor is not using the default by adding a noexcept(false).
When trying that on this example, we now get a different diagnostic from the compiler - that the destructor will never, ever reach the end. It's not good for a destructor to never fully destroy the object...
To "fix" this I had to make the rethrow conditional with an if.
class Txn
{
public:
Txn()
{
cout<< "in Constructor" << endl;
};
~Txn() noexcept(false)
{
try
{
cout << "in destructor" << endl;
throw 10;
}
catch(int i)
{
cout << "in destructor exception" << endl;
if (i == 10) throw;
}
}
};
Undefined behaviour can be anything, including a call to abort(); Just avoid everything that may induce it.
Throwing from the destructor is not forbidden, but doing that inside a try/catch might result in double exception thrown.
So we have a constructor that can throw an exception depending on the arguments passed to it, but we do not know how to delete the object if this occurs. Important part of the code:
try
{
GameBase *gameptr = GameBase::getGame(argc, argv);
if (gameptr == 0)
{
std::cout << "Correct usage: " << argv[PROGRAM_NAME] << " " << "TicTacToe" << std::endl;
return NO_GAME;
}
else
{
gameptr->play();
}
delete gameptr;
}
catch (error e)
{
if (e == INVALID_DIMENSION)
{
std::cout << "Win condition is larger than the length of the board." << std::endl;
return e;
}
}
catch (...)
{
std::cout << "An exception was caught (probably bad_alloc from new operator)" << std::endl;
return GENERIC_ERROR;
}
In the third line, GameBase::getGame() calls the constructor for one of the games derived from GameBase and returns a pointer to that game, and these constructors can throw exceptions. The question is, how can we then delete the (partial?) object pointed to by gameptr if this occurs? If an exception is thrown, we will exit the scope of gameptr because we leave the try block and cannot call delete gameptr.
To assess the exception safety, you need to provide more detail of the construction of the object in GameBase::getGame.
The rule is through, that if a constructor throws, the object is not created, hence the destructor is not called. Associated memory allocations are also deallocated (i.e. the memory for the object itself).
The issue then becomes, how was the memory allocated to begin with? If it was with a new GameBase(...), then there is no need to deallocate or delete the resultant pointer - the memory is deallocated by the runtime.
For clarity on what happens to the member variables that are already constructed; they are destructed on the exception of the "parent" object. Consider the sample code;
#include <iostream>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
M m_;
C() { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};
auto main() -> int {
try {
C c;
}
catch (exception& e) {
cout << e.what() << endl;
}
}
The output is;
M ctor
C ctor
M dtor
std::exception
If the M m_ member is to be dynamically allocated, favour a unique_ptr or a shared_ptr over a naked pointer, and allow the smart pointers to manage the object for you; as follows;
#include <iostream>
#include <memory>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
unique_ptr<M> m_;
C() : m_(new M()) { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};
The output here mirrors the output above.
When you write Foo* result = new Foo(), the compiler translates this to the equivalent of this code:
void* temp = operator new(sizeof(Foo)); // allocate raw memory
try {
Foo* temp2 = new (temp) Foo(); // call constructor
result = temp2;
} catch (...) {
operator delete(temp); // constructor threw, deallocate memory
throw;
}
So you don't need to worry about the allocated memory if the constructor throws. Note, however, that this does not apply to extra memory allocated within the constructor. Destructors are only called for objects whose constructor finished, so you should get all your allocations into small wrapper objects (smart pointers) immediately.
If you throw in a constructor, the object is not constructed and thus, you are responsible for the deletion of allocated resources. This goes even further! Consider this Code
int a = function(new A, new A);
It is up to the compiler in which ordering is the A allocated AND constructed. You might end up with an memory leak, if your A constructor can throw!
Edit:
Use instead
try{
auto first = std::make_unique<A>();
auto second = std::make_unique<A>();
int a = function(*first, *second);
...