Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why exceptions from unique_ptr destructor terminates the program?

Take a look at this code which causes program to terminate without catching the exception.

#include <iostream>
#include <string>
#include <memory>
#include <stdexcept>
using namespace std;

struct test {
  ~test() noexcept(false) {
    throw runtime_error("-my-cool-exception-");
  }
};

int main()
{
  try {
    auto ptr = unique_ptr<test>(new test());
    //test t; // this is ok, without unique_ptr<test> it works fine.
  }
  catch(exception& e) {
    cout << "this is not called, the program is aborted";
    cout << e.what() << endl;
  }
  return 0;
}

This question is different from stack overflow question: throwing exceptions out of destructor.

The difference is that only when I use unique_ptr<test> the exception is not caught.

You can see the live code, edit and compile here http://cpp.sh/9sk5m

like image 335
amin Avatar asked Jun 13 '16 11:06

amin


1 Answers

That's required by the standard. As per unique.ptr.single.dtor, 20.10.1.2.2.1:

Requires: The expression get_deleter()(get()) shall be well formed, shall have well-defined behavior, and shall not throw exceptions. [ Note: The use of default_delete requires T to be a complete type. — end note ]

(emphasis mine)

So really, it doesn't matter whether you destructor itself has noexcept(false) or not. It's forbidden to throw in this case – final word.

This is the case in general the case std:: – except when specified otherwise. As per res.on.functions, 17.6.4.8.2.4:

In particular, the effects are undefined in the following cases: [...] if any replacement function or handler function or destructor operation exits via an exception, unless specifically allowed in the applicable Required behavior: paragraph.

(emphasis mine)

Note: In general, you can have throwing destructors with noexcept(false). However, this is very dangerous, as std::terminate will be called if the stack was unwinding due to a thrown exception. As per except.ctor, 15.2.1:

As control passes from the point where an exception is thrown to a handler, destructors are invoked by a process, specified in this section, called stack unwinding. If a destructor directly invoked by stack unwinding exits with an exception, std::terminate is called ([except.terminate]). [ Note: Consequently, destructors should generally catch exceptions and not let them propagate out of the destructor. — end note ]

(emphasis mine)

See it live on Coliru.

like image 63
Ven Avatar answered Oct 26 '22 17:10

Ven