4

Suppose there is this code:

class CFoo
{
public:
    CFoo()
    {
        iBar = new CBar();
    }
private:
    CBar* iBar;
};

....
CFoo* foo = new CFoo();

When the above line is executed, first memory will be allocated to hold the CFoo object. But then if the line new CBar() throws an exception (due to lack of memory) does the system automatically deallocate the memory that was previously allocated to the CFoo object? I presume it must, but cannot find any explicit reference saying so. If it doesn't how can the memory be deallocated by the coder as it will not have been assigned to foo?

Etienne de Martel
  • 30,360
  • 7
  • 86
  • 102
David Preston
  • 1,771
  • 2
  • 11
  • 10
  • 2
    See: http://stackoverflow.com/questions/810839/throwing-exceptions-from-constructors and http://stackoverflow.com/questions/1230423/c-handle-resources-if-constructors-may-throw-exceptions-reference-to-faq-17 and http://stackoverflow.com/questions/1197566/is-it-ever-not-safe-to-throw-an-exception-in-a-constructor – user470379 Jan 17 '11 at 20:41
  • I do not think memory was allocated if you got an exception – Elalfer Jan 17 '11 at 20:43
  • 2
    you might want to accept some of the answers to your previous 5 questions. – Sam Miller Jan 17 '11 at 20:45

4 Answers4

6

Yes, the memory allocated for the CFoo object will be freed in this case.

Because the exception due to the failed allocation causes the CFoo constructor to fail to complete successfully the new-expression is guaranteed to free the memory allocated for that CFoo object.

This guarantee is specified in 5.3.4 [expr.new] / 17 of ISO/IEC 14882:2003.

Note, that it is always advisable to assign the result of a dynamic allocation to a smart pointer to ensure proper clean up. For example, if there was further code in CFoo constructor and that threw an exception the CBar object already successfully allocated earlier in the constructor would be leaked.

CB Bailey
  • 648,528
  • 94
  • 608
  • 638
3

Yes, but consider what happens if there's more than one member pointer:

class CFoo
{
public:
    CFoo()
    {
        iBar = new CBar();
        iBaz = new CBaz(); // Throws an exception
    }
private:
    CBar* iBar;
    CBaz* iBaz;
};

....
CFoo* foo = new CFoo();

Now the CBar object will be leaked. Using smart pointers instead of native pointers would take care of this.

Also, prefer to use member initializers:

class CFoo
{
public:
    CFoo() : iBar(new CBar())
    {
        // Nothing here
    }
private:
    CBar* iBar;
};

....
CFoo* foo = new CFoo();
Fred Larson
  • 56,061
  • 15
  • 106
  • 157
1

Yes- the memory is automatically freed. Consider the following simplified pseudo of operator new:

template<typename T> T* operator new() {
    void* ptr = nullptr;
    try {
        ptr = ::operator new(sizeof(T));
        return new (ptr) T();
    } catch(...) {
        ::operator delete(ptr);
        throw;
    }
}
Puppy
  • 138,897
  • 33
  • 232
  • 446
  • 1
    I know this is "pseudo" code, but I think that it is very misleading. It's called `operator new` but it has nothing to do with `operator new`, it replicates what a non-placement _new expression_ preforms. It uses `malloc` but a _new-expression_ **must** use an `operator new`. The `static_cast` is unnecessary, the placement new expression will evaluate to a correctly typed point for the type being constructed. – CB Bailey Jan 17 '11 at 20:51
  • More importantly than "pseudo" was "simplified". The only important behaviour of the above is how it behaves with regards to exceptions. However, using malloc/free was a mistake. – Puppy Jan 17 '11 at 20:54
  • Isn't new supposed to return a void pointer irregardless of what type it actually returns? that into a namespace else you'll have a circular reference. – wheaties Jan 17 '11 at 21:00
0

If you are going to rely on compiler-supplied operator new, then in the above case, the destructor will not be called. The reason being: when new CBar() throws an exception, stack unwinding starts happening immediately, and the object CFoo is not "fully" constructed. Since it is half constructed object, the compiler does not call destructor for CFoo.

Rule of thumb: destructor is called only for fully constructed objects in C++

Viren
  • 2,123
  • 22
  • 27
  • The question is asking whether the memory for the object is deallocated, not whether the destructor is called (which, as you say, it shouldn't be because the object will not have been constructed yet). – CB Bailey Jan 17 '11 at 21:03
  • 1
    In fact, any subobject that has been *fully constructed* will have its constructor called: `struct test { test() : a(), b(), c() {} type a,b,c; }` If the `c()` constructor throws, it's destructor will not be called and neither will `test` destructor, but `a` and `b` destructors will be called as those have been *fully* constructed by the time the exception is thrown. – David Rodríguez - dribeas Jan 17 '11 at 21:08