How to gurantee destructor is called in exception handling ?

I have two sample codes written by my prof.

1.
1
2
3
4
5
6
7
8
9
10
11
void error_test8() {
    // v has a private pointer to an underlying array on the free store
    vector<int> v = {1, 2, 3, 4, 5};

    try {
        error("testing 1, 2 ,3");
    } catch (...) {
        cout << "Caught some exception\n";
    }
    // uh oh: what about the underlying array belonging to v?
 }


C++ exceptions guarantee that destructors are properly called, and so the destructor for v is called here. However, it is possible for the vector<int> constructor to throw an exception (e.g. bad_alloc due to running out of memory). So it is safer to do this:

2.
1
2
3
4
5
6
7
8
9
10
11

void error_test9() {
    try {
        vector<int> v = {1, 2, 3, 4, 5};
        error("testing 1, 2 ,3");
    } catch (...) {
        cout << "Caught some exception\n";
    }
    // v's destructor is guaranteed to be called
}


Again, if any exception is thrown by any statement in the try block, it will be caught by catch (...), and vs destructor is guaranteed to always be called. This guarantee of calling destructors when exceptions occur is extremely useful in practice.


*** Question ***
By exception is he referring to the try block {} ? Could you please specifically point out which part of the second sample code causes destructors to be called ?
So it is safer to do this

No, it isn't.

If a constructor throws, object lifetime hasn't yet begun (because the constructor didn't complete), so there's no need to worry about destroying it.

The first example is correct; resources allocated by v will never leak in this case.

The only time a resource contained in v could leak is if an element it contained threw an exception from its destructor while v was being destroyed.

Edit:
To answer your question, objects with automatic storage duration are destroyed properly when they go out of scope. This is immaterial as to whether they go out of scope thanks to stack unwinding or a normal control flow, but it is guaranteed to happen as long as you don't e.g., call a function which doesn't return, or call longjmp or something.

It doesn't matter whether you catch the exception or not. Properly written exception-safe code will guarantee by default that every resource will be released even in presence of exceptions; the standard library provides facilities which do this by default, including std::vector.

Your professor needs to read about RAII.
Last edited on
> Could you please specifically point out which part of the second sample code causes destructors to be called ?

test8:
If an exception was thrown by the constructor of v, the object v was never initialised, and its destructor will never be (can not be) called.

If the constructor of v completed (the constructor did not throw) its destructor will be called when its life-time ends, on exit from the function.


test9:
If an exception was thrown by the constructor of v, the object v was never initialised, and its destructor will never be (can not be) called.

If the constructor of v completed, and if the function error() throws, its destructor will be called as part of the stack-unwind.

If the constructor of v completed and the function error() did not throw, its destructor will be called when its life-time ends, on exit from the try block.

Unless we want to handle allocation failure (out of memory errors), do not wrap the constructor of the vector within a try block. The first snippet (test8) is saner than the second one (test9).

The prof who believes that test9 is safer than test8 should be trying to learn C++ error-handling rather than attempting to teach it.
to be fair, that example easy to make useful, if the vector is not hard-coded but depends on external data:

1
2
3
4
5
6
7
8
void process_packet(const Packet& p) {
    try {
        vector<int> v(p.size); // some hacker wrote -1 in the size field of this packet
        decode(p.contents, v.data());
    } catch (...) {
        cout << "Corrupt packet skipped\n";
    }
}
Last edited on
Topic archived. No new replies allowed.