Rafa
Rafa

Reputation: 1151

C++ bad_alloc thrown in a constructor

When a bad_alloc exception is thrown in a constructor, in which multiple objects are created, what must be done to clean up the memory. Ex.

class Object
{
   private:
     A * a;
     B  * b;

 public:

   Object()
   {
       a= new A();
       b= new B(); //So if a bad_alloc is called here, how is a deleted???
   }
} 

My intuition is to place each call to new in a separate try catch bloc, and delete all objects for which new was called previously but this is too verbose (the first try bloc calls no destructor, the second class that of the first, the 3rd calls that of the first two etc). My question is: What is the most common way to handle this?

Also, lets say the class objects contains a object not created with new (because it is on the stack), is its destructor called automatically?

Upvotes: 1

Views: 2861

Answers (2)

CashCow
CashCow

Reputation: 31445

Firstly I fixed your code because it is a C++ question, so it has to be written as C++. A constructor might fail with exceptions other than bad_alloc.

Your options are there:

  • Do not store pointers but store the objects. These are constructed automatically (or via the initialiser list) and yes will automatically be cleaned up if created. This can be better but means they need to be fully defined, i.e. their headers included, and you may be trying to hide your implementation detail / decouple..

  • Store some kind of smart pointer like unique_ptr which is really an object so gets cleaned up like an object, deleting the underlying pointer if there is one.

  • Store a regular pointer in your class but use unique_ptr (or auto_ptr if unique_ptr is not available) during the constructor and, at the end when you know everything has constructed properly, you can release your smart pointers into your member variables.

The latter solution would look like:

 // header file
 //
class A; // implementation hidden on purpose
class B; // ditto

class Object
{
   private:
      A * a;
      B * b;

   public:
     Object();
     ~Object();

    private:

 // if not using C++11 do not put in =delete but still declare these

    Object( const Object & ) = delete;
    Object& operator=( const Object & ) = delete;

};

// cpp file

#include "object.h"
#include "a.h"
#include "b.h"

Object::Object()
   : a( nullptr ), // use NULL or 0 if nullptr not available
     b( nullptr )
{
    std::unique_ptr< A > pa( new A ); // might throw
    std::unique_ptr< B > pb( new B ); // might throw (1)

    a = pa.release(); // cannot throw
    b = pb.release(); 
}

Object::~Object()
{
     delete b;
     delete a;
}

(1) if it throws pa which is local will have its destructor invoked which will delete the pointer you created with new.

Note: if you don't have unique_ptr available, auto_ptr will serve just as well here.

Upvotes: 2

Paul Evans
Paul Evans

Reputation: 27577

You want to use smart pointers:

class Object {
    std::unique_ptr<A> a;
    std::unique_ptr<B> b;

public:
    Object() : a(make_unique<A>()), b(make_unique<B>()) {}
}

Upvotes: 6

Related Questions