1
votes

I'm reading Scott Meyerses C++ and now I'm at the destructor throwing exceptions section. Here is what is he said:

When the vector v is destroyed, it is responsible for destroying all the Widgets it contains. Suppose v has ten Widgets in it, and during destruction of the first one, an exception is thrown. The other nine Widgets still have to be destroyed (otherwise any resources they hold would be leaked), so v should invoke their destructors. But suppose that during those calls, a second Widget destructor throws an exception. Now there are two simultaneously active exceptions

So, as far as I undesrstood it, if the first element of a vector throws an exception it doesn't mean the program to be terminated right after that. The implementation tries to destroy the other objects in the vector instead. Let me provide an example:

#include<iostream>
#include<vector>

struct A
{
    ~A(){ std::cout << "destruction" << std::endl; throw std::exception(); }
};

int main()
{
    A a[] = {A(), A(), A(), A(), A(), A()};
    std::vector<A> v;
    v.assign(a, a+6);
}

DEMO

The program was terminated right after the first exception throwing. Where is the promised the second exception throwing?

2
I don't have the book handy at the moment, but from what I recall, it's a hypothetical. It explains why the language doesn't actually work this way - because if it tried to work this way, it would lead to absurd outcomes. It also explains why it's a really bad idea to ever throw from a destructor.Igor Tandetnik
Aside from being a bad idea, you never catch the first exception so the program terminates before it can even begin to destroy the other objects.user657267
@user657267 ... and indeed, it's not trivial to catch it, because it's in a destructor.kfsone

2 Answers

4
votes

If a destructor invoked by a standard library component exits via an exception, the behavior is undefined. [res.on.functions]/p2, emphasis mine:

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.
  • [...]
2
votes

You're referring to Item 8 "Prevent exceptions from leaving destructors". Your quote of the text truncates it mid sentence:

Now there are two simultaneously active exceptions, and that's one too many for C++. Depending on the precise conditions under which such pairs of simultaneously active exceptions arise, program execution either terminates or yields undefined behavior.

You indicate that you "undesrstood it, if the first element of a vector throws an exception it doesn't mean the program to be terminated right after that"

Well, it does if you don't catch it, because that's what uncaught exceptions do.

Alternatively, you catch it. By doing so, you have left the frame of execution that was doing the destruction, and so whatever was going on is no-longer going on.

// speculative "what if"

struct A { ~A() { raise std::exception(); } };

void f() {
   A a, b;
} // b and a go out of scope, the first one throws

int main() {
    try {
        f();
    } catch (...) {
        // << program is now here.
    }
}

There is no mechanism to "resume" the termination code for f(), an exception occurred, that code path is done, so if it was a that destructed, b will never destruct; or vice versa.

Ok, you were talking about a vector. So you perceive that, say, std::vector::clear is doing something like:

clear() {
    while (!empty()) {
        try {
            erase(back());
        } catch (std::exception& e) {
            // something went wrong, lets ignore it
        }
        m_size--;
    }
}

Your understanding that "if an exception occurs, the implementation tries to destroy the other objects in the vector instead" is false. As Meyers says, the STL doesn't expect or encourage exceptions from destructors, so it doesn't try to handle them. I don't know where you got this understanding from, but it's inaccurate, sorry, and if the language tried to implement it, we'd be in a real mess because if something went wrong enough to generate an exception while trying to destroy an object, things would get really messy.