views:

407

answers:

7

I really can't believe I couldn't find a clear answer to this...

How do you free the memory allocated after a C++ class constructor throws an exception, in the case where it's initialised using the "new" operator. E.g.:

class Blah
{
public:
  Blah()
  {
    throw "oops";
  }
};

void main()
{
  Blah* b = NULL;
  try
  {
    b = new Blah();
  }
  catch (...)
  {
    // What now?
  }
}

When I tried this out, "b" is NULL in the catch block (which makes sense).

When debugging, I noticed that the conrol enters the memory allocation routine BEFORE it hits the constructor.

This on the MSDN website seems to confirm this:

When new is used to allocate memory for a C++ class object, the object's constructor is called after the memory is allocated.

So, bearing in mind that the local variable "b" is never assigned (i.e. is NULL in the catch block) how do you delete the allocated memory?

It would also be nice to get a cross platform answer on this. i.e., what does the C++ spec say?

CLARIFICATION: I'm not talking about the case where the class has allocated memory itself in the c'tor and then throws. I appreciate that in those cases the d'tor won't be called. I'm talking about the memory used to allocate THE object ("Blah" in my case).

Cheers.

John

A: 

From C++ FAQ (parashift.com):

[17.4] How should I handle resources if my constructors may throw exceptions?

Every data member inside your object should clean up its own mess.

If a constructor throws an exception, the object's destructor is not run. If your object has already done something that needs to be undone (such as allocating some memory, opening a file, or locking a semaphore), this "stuff that needs to be undone" must be remembered by a data member inside the object.

For example, rather than allocating memory into a raw Fred* data member, put the allocated memory into a "smart pointer" member object, and the destructor of this smart pointer will delete the Fred object when the smart pointer dies. The template std::auto_ptr is an example of such as "smart pointer." You can also write your own reference counting smart pointer. You can also use smart pointers to "point" to disk records or objects on other machines.

By the way, if you think your Fred class is going to be allocated into a smart pointer, be nice to your users and create a typedef within your Fred class:

 #include <memory>

 class Fred {
 public:
   typedef std::auto_ptr<Fred> Ptr;
   ...
 };

That typedef simplifies the syntax of all the code that uses your objects: your users can say Fred::Ptr instead of std::auto_ptr:

 #include "Fred.h"

 void f(std::auto_ptr<Fred> p);  // explicit but verbose
 void f(Fred::Ptr           p);  // simpler

 void g()
 {
   std::auto_ptr<Fred> p1( new Fred() );  // explicit but verbose
   Fred::Ptr           p2( new Fred() );  // simpler
   ...
 }
JRL
That's talking about the object's contents, whereas I think the original poster is asking explicitly about the memory allocated to put the object in.
Kylotan
Does not answer the question.
Martin York
This addresses a related question--not the one asked. This tells you how to write `Blah` so that `Blah` can clean up anything it allocates before throwing an exception. The question is about who cleans up the memory allocated for `Blah` itself.
Adrian McCarthy
A: 

I think it's kind of wierd for a constructor to raise an exception. Could you have a return value and test it in your main?

class Blah { public:

Blah()
{
if Error { this.Error = "oops";
} } };

void main() {
Blah* b = NULL;

b = new Blah();

if (b.Error == "oops") { delete (b); b = NULL; }

Danielle
An exception is the right tool in this instance. Setting a flag value may be used be only if you can't uses Exceptions.
JRL
To be honest, I think this would be even worse as it is not clear to the user that when the constructor succeeded the object is still in an inconsistent state. Leaving it to others to clean up your mess is no good style. I'd prefer the exception-way if you cannot get the error-causing stuff out of your constructor.
Kosi2801
A return value that you have to test is exactly what we _don't_ want to have! That's what we've had in plain old C for thirty years, and how many billions of ignored return values do we have out there now???
Thomas Padron-McCarthy
The standard way to do it is with exceptions, and there's nothing weird about it. Return values like that have not historically been a success. With exceptions, either we have a usable object or we don't, so we can use it without a test we're likely to forget.
David Thornley
+11  A: 

You should refer to the similar questions here and here. Basically if the constructor throws an exception you're safe that the memory of the object itself is freed again. Although, if other memory has been claimed during the constructor, you're on your own to have it freed before leaving the constructor with the exception.

For your question WHO deletes the memory the answer is the code behind the new-operator (which is generated by the compiler). If it recognizes an exception leaving the constructor it has to call all the destructors of the classes members (as those have already been constructed successfully prior calling the constructor code) and free their memory (could be done recursively together with destructor-calling, most probably by calling a proper delete on them) as well as free the memory allocated for this class itself. Then it has to rethrow the catched exception from the constructor to the caller of new. Of course there may be more work which has to be done but I cannot pull out all the details from my head because they are up to each compiler's implementation.

Kosi2801
How exactly is the memory freed? I'm interested especially in the case where someone may be using their own operator new, for example.
Kylotan
clarified in my answer.
Kosi2801
Your own implementations of operators new and delete only have to know how to allocate and release memory. The extra work is done by the compiler. When you say `new Blah()`, the compiler generates code to (1) call the new operator (which just allocates memory), (2) call the c'tor, and (3) call the delete operator if something goes wrong.
Adrian McCarthy
@Adrian: Just to be pedantic ;-) Calls (3) if (1) completes and (2) throws.
Martin York
Phew, great I thought I was going mad :-). Thanks for the answer.
John
PS: Apologies for asking an already covered question - I did have a quick look first, but couldn't see this specific question.
John
+2  A: 

The long and short of it is that if you haven't made any allocations of other entities in you object(as in your example) then the memory that was allocated will be deleted automatically. However, any new statements(or anything else that directly manages memory) needs to be handled in a catch statement in the constructor, Otherwise the object is deleted without deleting it's subsequent allocations and you, my friend, have a leak.

kramthegram
+2  A: 

If the Constructor throws the memory allocated for the object is auto-magically returned to the system.

Note the destructor of the class that threw will not be called.
But the destructor of any base class (where the base constructor has completed) will also be called.

Note:
As most other people have noted members may need some clean up.

Members that have been fully initialized will have their destructors called, but if you have any RAW pointer members that you own (ie delete in the destructor) you will have to do some clean up before you do the throw (another reason not to use owned RAW pointers in your class).

#include <iostream>

class Base
{
    public:
        Base()  {std::cout << "Create  Base\n";}
        ~Base() {std::cout << "Destroy Base\n";}
};

class Deriv: public Base
{
    public:
        Deriv(int x)    {std::cout << "Create  Deriv\n";if (x > 0) throw int(x);}
        ~Deriv()        {std::cout << "Destroy Deriv\n";}
};

int main()
{
    try
    {
        {
            Deriv       d0(0);  // All constructors/Destructors called.
        }
        {
            Deriv       d1(1);  // Base constructor and destructor called.
                                // Derived constructor called (not destructor)
        }
    }
    catch(...)
    {
        throw;
        // Also note here.
        // If an exception escapes main it is implementation defined
        // whether the stack is unwound. By catching in main() you force
        // the stack to unwind to this point. If you can't handle re-throw
        // so the system exception handling can provide the appropriate
        // error handling (such as user messages).
    }
}
Martin York
+7  A: 

If an object cannot complete destruction because the constructor throws an exception, the first thing to happen (this happens as part of the constructor's special handling) is that all member variables to have been constructed are destroyed - if an exception is thrown in the initializer list, this means that only elements for which the initializer has completed are destroyed.

Then, if the object was being allocated with new, the appropriate deallocation function (operator delete) is called with the same additional arguments that were passed to operator new. For instance, new (std::nothrow) SomethingThatThrows() will allocate memory with operator new (size_of_ob, nothrow), attempt to construct SomethingThatThrows, destroy any members that were successfully constructed, then call operator delete (ptr_to_obj, nothrow) when an exception is propagated - it won't leak memory.

What you have to be careful is allocating several objects in succession - if one of the later ones throws, the previous ones will not be automatically be deallocated. The best way around this is with smart pointers, because as local objects their destructors will be called during stack unwinding, and their destructors will properly deallocate memory.

coppro
+1, looks like the most relevant answer
Johannes Schaub - litb
+1  A: 

From the C++ 2003 Standard 5.3.4/17 - New:

If any part of the object initialization described above terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression. If no unambiguous matching deallocation function can be found, propagating the exception does not cause the object’s memory to be freed. [Note: This is appropriate when the called allocation function does not allocate memory; otherwise, it is likely to result in a memory leak. ]

So there may or may not be a leak - it depends on whether an appropriate deallocator can be found (which is normally the case, unless operator new/delete have been overridden).In the case where there's a suitable deallocator, the compiler is responsible for wiring in a call to it if the constructor throws.

Note that this is more or less unrelated to what happens to resources acquired in the constructor, which is what my first attempt at an answer discussed - and is a question that is discussed in many FAQs, articles, and postings.

Michael Burr