chihyang
chihyang

Reputation: 187

Ways to avoid memory leak when exception thrown

This is an exercise from C++ Primer, chapter 18:

void exercise(int *b, int *e)
{
    vector<int> v(b, e);
    int *p = new int[v.size()];
    ifstream in("ints");
    // exception occurs here
}

The code above would cause memory leak, because the memory we manage directly (i.e. p) is not automatically freed when an exception occurs.

Exercise 18.3:

There are two ways to make the previous code work correctly if an exception is thrown. Describe them and implement them.

I know we can use smart pointer to avoid this pitfall:

void exercise(int *b, int *e)
{
    vector<int> v(b, e);
    unique_ptr<int[]> p(new int[v.size()]);
    ifstream in("ints");
    // exception occurs here
}

or:

void exercise(int *b, int *e)
{
    vector<int> v(b, e);
    shared_ptr<int> p(new int[v.size()], [](int *p){ delete[] p; });
    ifstream in("ints");
    // exception occurs here
}

I'm not sure if these are TWO ways. After all, they are the same virtually. So I thought of another way:

void exercise(int *b, int *e)
{
    vector<int> v(b, e);
    int *p = new int[v.size()];
    ifstream in("ints");
    // exception occurs here
    if(!in)
        throw p;
}

// caller
try {
    exercise(b, e);
} catch (int *err) {
    delete[] err; // initialize err with b and delete e.
}

If exception occurs, throw p to initialize another pointer and delete that one. I know this is not a perfect solution, because other exceptions might occur so that I don't even have a chance to throw p. But I can't think of a better one. Could you help to find the second way?

Upvotes: 6

Views: 903

Answers (1)

John Zwinck
John Zwinck

Reputation: 249093

You can explicitly catch and re-throw the exception:

void exercise(int *b, int *e)
{
    vector<int> v(b, e);
    int *p = new int[v.size()];
    try {
        ifstream in("ints");
        // exception occurs here
    } catch (...) {
        delete[] p;
        throw;
    }
    delete[] p;
}

Of course this doesn't work so well if you have multiple resources to free, because you may end up with nested try/catch blocks. Not to mention that you have two deletes for one new. So RAII is preferred.

Upvotes: 4

Related Questions