c++ destructor throw exception by single object - c++

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.

Related

Exception handler catch(...) in C++

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.)

How function-level exception handling works?

There is the following code, from here
class Base {
int i;
public:
class BaseExcept {};
Base(int i) : i(i) { throw BaseExcept(); }
};
class Derived : public Base {
public:
class DerivedExcept {
const char* msg;
public:
DerivedExcept(const char* msg) : msg(msg) {}
const char* what() const { return msg; }
};
Derived(int j) try : Base(j) {
// Constructor body
cout << "This won't print" << endl;
}
catch (BaseExcept&) {
throw DerivedExcept("Base subobject threw");;
}
};
int main() {
try {
Derived d(3);
}
catch (Derived::DerivedExcept& d) {
cout << d.what() << endl; // "Base subobject threw"
}
}
My question is, why the thrown exception is not caught here
catch (BaseExcept&) {
throw DerivedExcept("Base subobject threw");;
}
But the catch in main?
catch (Derived::DerivedExcept& d) {
cout << d.what() << endl; // "Base subobject threw"
}
Why does it output "Base subobject threw"
According to my understanding, the thrown exception should be caught in the catch after try (or the function body equivalent to try), but there is no, why?
What is the propagation path of the exception?
code from there
My question is this, try catch I have seen before all have this form.
try{}
catch(){}
So I think for the following snippet
Derived(int j) try: Base(j) {
// Constructor body
cout << "This won't print" << endl;
}
catch (BaseExcept&) {
throw DerivedExcept("Base subobject threw");;
}
When Derived() throws an exception, it should be caught by the catch (BaseExcept&)in the following line, not by the catch (Derived::DerivedExcept& d) in the main function.
But when I comment out it here
catch (Derived::DerivedExcept& d) {
//cout << d.what() << endl; // "Base subobject threw"
}
There will be no "Base subobject threw" output.
This is different from what I expected. I am learning basic exception knowledge. Did I understand something wrong
Derived(int j) try : Base(j) {
// Constructor body
cout << "This won't print" << endl;
}
catch (BaseExcept&) { // why the thrown exception is not caught here
throw DerivedExcept("Base subobject threw");;
}
The only way for the program to output Base subobject threw is if the exception is actually caught where you do not think it's caught. The string does not exist anywhere else in the program.
But the catch in main?
That's because you throw an exception in the catch. That exception is not caught by the same catch (which would result in infinite recursion in this case). It's caught by the outer try..catch which you have in main.

Program ends with "abort() has been called" error on VS2017

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.

How to delete object if constructor throws an exception?

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);
...

How does this piece of cpp code dump?

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.