1

I'm trying to understand why the destructors throwing exceptions is a very bad idea. By googling, I understand that if destructor throws, say, during destruction of the block-scope objects, the destruction of the obeject stopped and we get memory leak if there're the other objects destructors have not called for.

But by itself, the destructor throwing exceptions is so bad? For instance (the complete example):

struct A
{
    int a;
    char b;
    A() : a(10), b('a') { }
    ~A(){ throw std::exception(); }
};

int main()
{
    A a; //destructor throws, but there're no more objects to destruction 
         //therefore I think there's no memory leak
}

Do we get UB in the program above?

St.Antario
  • 26,175
  • 41
  • 130
  • 318
  • In this program there isn't a memory leak, since the program exits immediately due to the fact that a thrown exception wasn't caught. The struct `A` *does* have a problem, if it ends up being used in any non-trivial manner. I'm not quite sure about the Undefined Behavior question though, I'm not a language-lawyer for C++. – Daniel Jun 29 '15 at 04:10
  • And what exactly do you plan to do with this exception?? – Swastik Padhi Jun 29 '15 at 04:11
  • @Daniel I know that we don't ever do such things in real code, but try to undestand the UB though. – St.Antario Jun 29 '15 at 04:12
  • @CRAKC Nothing, it's just an example... – St.Antario Jun 29 '15 at 04:13
  • If your main has a try/catch block, there wouldn't be any UB and all's good, but you'd have trouble taking `A` and using it in a more complicated program. There are lots of existing Q&A about the issues, e.g. [here](http://stackoverflow.com/questions/130117/throwing-exceptions-out-of-a-destructor?rq=1). – Tony Delroy Jun 29 '15 at 04:13
  • @Daniel BTW, the destructor throwing exception allows the object being destructed to destroyed correctly? – St.Antario Jun 29 '15 at 04:14
  • @TonyD As you can see, there's no try-catch. – St.Antario Jun 29 '15 at 04:14
  • @St.Antario: Undefined Behavior means just that. It is "Undefined". It might do what you expect, but it might be that the compiler decides to format C:. If it is "Undefined" by the standard, and Undefined by your specific implementations, then you have no way of knowing what could happen. It is even possible that exception mechanism mess with the stack in ways that are incompatible with destructor unwinding. – Daniel Jun 29 '15 at 04:15
  • @St.Antario: yes, I can see that... my meaning was more "if you *add* a `try`/`catch`".... Without such a block, `std::terminate()` will be called, and it's implementation-defined whether the stack will be unwound beforehand. (Per 15.3/9). The behavior is *not* undefined, but it's silly to `throw` without `catch`ing.... – Tony Delroy Jun 29 '15 at 04:15

1 Answers1

6

In this trivial example, the exception in bar() is thrown and the stack is unwound, destructing a, which throws another exception. Which exception could be thrown in this case?

struct A
{
    int a;
    char b;
    A() : a(10), b('a') { }
    ~A(){ throw std::exception(); }
};
void bar () 
{
    A a;
    throw std::exception();
}
int main()
{
    bar();
}

From C++ FAQ

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.

So the C++ language guarantees that it will call terminate() at this point, and terminate() kills the process.

ixSci
  • 13,100
  • 5
  • 45
  • 79
twsaef
  • 2,082
  • 1
  • 15
  • 27