bananov
bananov

Reputation: 173

Why aren't destructors called when exception isn't caught within main?

I have the following code:

#include <iostream>
#include <vector>
#include <tr1/memory>

struct FooError {};

struct Foo
{
    ~Foo() { std::cerr << "~Foo() executed" << std::endl; }
    explicit Foo(unsigned int index) { if (5 == index) throw FooError(index); };
};


int main() {
    typedef std::tr1::shared_ptr<Foo> FooPtr;
    std::vector<FooPtr> foos;
    for (unsigned int index = 0; index < 20; ++index)
    {
        try
        {
            foos.push_back(FooPtr(new Foo(index)));
        }
        catch (const FooError&)
        {
            std::cerr << "FooError caught" << std::endl;
        }
    }
}

I see a set of ~Foo() executed when there are try{} catch{} blocks. When there are no exception handlers, nothing is printed. Does it mean that destructors of stack-allocated objects are called when exception is handled? Or is nothing printed because of std::cerr buffering issues?

Upvotes: 2

Views: 302

Answers (4)

Kerrek SB
Kerrek SB

Reputation: 476910

The program's scope unwinding, whether through normal execution or via try/throw/catch, only happens if the application exits by returning from main. If the application exits via an exception (or via abort() or terminate()), no unwinding happens and no destructors get called.

This pertains to both automatic and static objects.

Upvotes: 3

Michael Burr
Michael Burr

Reputation: 340168

Here are the details of what's going on from the C++03 standard.

  • From 15.3/9 Handling Exceptions

    If no matching handler is found in a program, the function terminate() is called;

  • From 18.6.3 Abnormal termination:

    The implementation’s default terminate_handler calls abort().

  • And from 3.6.3/4 Termination:

    Calling the function void abort(); declared in <cstdlib> terminates the program without executing destructors for objects of automatic or static storage duration and without calling the functions passed to atexit().

So that's why your foos object isn't being destructed (it has static storage duration). However, even if you change it so that it's a local variable (having automatic duration), that might not fix the problem (emphasis added):

So for static duration objects, destructors aren't called unless you change the terminate handler (maybe to have it call exit() instead of abort()). However, for automatic objects, there remains a possible problem (emphasis added):

15.5.1/1 The terminate() function

In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before terminate() is called. In all other situations, the stack shall not be unwound before terminate() is called.

Upvotes: 5

Pubby
Pubby

Reputation: 53017

The destructors are being called (from the vector) after the loop, right before the program exits.

If you don't catch the exception, terminate is called which aborts the program without calling destructors.

Upvotes: 2

bashirs
bashirs

Reputation: 450

If you catch the exception the deallocators will be called to clean up the memory. If you dont catch the exception the application will just quit.

A vector actually stores all its data on the heap by the way; that is why it is resizable. You can think of the data on the stack as being a pointer to the memory on the heap (which is hidden from you).

Upvotes: 1

Related Questions