1
class A // blah blah generic abstracty whatever
{
  public:
  A();
  ~A();
};

class B
{
  public:
  B();
  ~B();

  private:
  A* a[8];
};

B::B()
{
  for(int x = 0; x < 8; x++)
  {
    a[x] = new A;
  }
}

B::~B()
{
  for(int x = 0; x < 8; x++)
  {
    delete a[x];
  }
}

I'm just curious if the above code will leak on it's own. Is there any situation where it could leak (aside from if I didn't call delete properly)?

Thanks.

Lemmons
  • 1,598
  • 4
  • 21
  • 30

4 Answers4

9

Yes, it's possible if new throws in the constructor.

The destructor would then not be run and any allocations that had already happened will not be released.

To be more specific: if any memory has been dynamically allocated before an exception occurs in the constructor, a memory leak will occur because the destructor of the object will not run.


A simple illustration:

class Leaks
{
private:

    data* d;

public:

    Leaks()
    {
        data = new int;
        throw 1;
    }

    ~Leaks()
    {
        delete data;
    }

};

This is a flawed design. data will always leak here. There's nothing you can do about it. (The only case in which data wouldn't leak would be if the new failed.)

Since new itself can throw, your example code is capable of throwing after one or more allocations, thus leaving you with a leak.

There are three ways to deal with this:

  • Don't allocate memory (in this situation you would simply use a vector, but obviously sometimes there's no way around using dynamic allocations)
  • Make sure your constructor can never throw after any memory allocations or if it does throw to clean up the memory before throwing. This is going to make some pretty nasty code though in all but the most trivial of constructors
  • Use smart pointers
Corbin
  • 31,183
  • 6
  • 65
  • 77
  • The destructor will run for those objects - for which `new` was called! – Aniket Inge Mar 12 '13 at 06:16
  • @Aniket: No it won't. `a` is an array of *pointers* to `A`, not `A` themselves. – In silico Mar 12 '13 at 06:17
  • @Aniket no `B::~B` will not run at all if `B::B` throws; destructors are only run for completely constructed objects. – Stephen Lin Mar 12 '13 at 06:18
  • Thanks. You answered my question and more. – Lemmons Mar 12 '13 at 06:41
  • @Lemmons the answer above touches on this, but just in case it's unclear, you only have to clean up after the `new` allocations that succeeded: if a constructor of an object being allocated with `new` throws, the particular memory allocated for it is automatically deallocated. (if `new` fails due with `std::bad_alloc`, then no memory is allocated at all.) see [(this question)](http://stackoverflow.com/questions/4094996/what-happens-to-the-memory-allocated-by-new-if-the-constructor-throws) for more info... – Stephen Lin Mar 12 '13 at 06:51
1

No leaks. This code is fine - no leaks.

idoo
  • 300
  • 1
  • 11
1

Can't see any leaks or potential leaks there. About the only nasty bit is the hardcoded array size. If you were to change that to be dynamic, you might need to look into the delete[] operator.

John3136
  • 27,345
  • 3
  • 44
  • 64
1

It seems the code is proper. No leaks.

Subhajit
  • 304
  • 1
  • 6