Link to home
Start Free TrialLog in
Avatar of gysbert1
gysbert1

asked on

"new" and C++ exceptions in class constructors

How do I get around this without overloading the new operator on the class.

I have a basic C++ class that has storage and behaviour. As it is a factory class it needs to hit a database upon construction. Problem is that this can of course fail and the database library uses exceptions!

If I am not calling new everything is fine but if I use new to do dynamic allocation on the heap I run into the following scenario:

p = new MyClass(i);

1) Local storage is allocated on the heap.
2) Constructor is called with i as parameter.
3) Constructor fails with an exception which I catch.

All seems well except that the class local storage is never freed and the assignment to p is never made so I cannot free it either!

I know that I can get around this by overloading the new operator, creating a default constructor that only allocates space and then calling that and after that ...

It just seems to me that there must be a better way ?
Avatar of dhymes
dhymes

Are you breaking the basic rule of "Don't allocate any memory during construction of an object?". Since it is a class factory, why not create an instance of your database object and pass this in to your constructor, that way you can 1. Catch and report a database connection problem to the user. 2. Not break any coding standard rules. 3. Get around the problem you are having.

Sorry, you just hit a soft spot with me. Allocation of memory inside of a constructor should always be avoided. If you can not avoid it then you need to take another look at your application architecture.

Regards,
Dave
Let's consider a simple case:

    struct X
    {
        X() { throw 0; }
    };

Now, a trivial usage will cause a memory leak:

    X* p = new X;
    // do something...
    delete p;

However, it can be overcome by:

    X* p = 0;

    try {
        p = new X;
        // do something
    }

    catch (...) {
        // do something
    }

    delete p;
If new fails from an exception memory should be freed automatically. But basically alexo has a point:

  Y* y = new Y;
  X* x = new X(1);
  ...
  delete y;

If an exception is thrown during construction of the X object, the memory allocated to y is not released (the memory allocated to the X object is, I think, freed).

alexo painted one method:

  Y* y = new Y;

  X* x = 0;
  try{ x = new X(1); }
  catch(...){}
  ...
  delete y;

another way is to use auto_ptr

  auto_ptr<Y> y(new Y);

  X* x = new X(1);
  ...
  // auto_ptr always deletes the memory allocated to y.
ASKER CERTIFIED SOLUTION
Avatar of alexo
alexo
Flag of Antarctica image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Looking at the question again, gysbert1, how do you know that there is memory that is not freed?
Why don't you catch the exception int the constructor? then you can add a boolean m_isGood to the class and set it to true or false depending on the success of construction. You may add more members to get the details of error if needed.
Hmm.. just thought of something, can't he call "delete this;" from constructor?
what will happen then ?
{
  MyClass m;
}
As mentioned, the problem is not the memory allocated for the MyClass object. Leaks may arise from objects that have been constructed during construction of the MyClass object. You may think you did a good job by releasing resources in MyClass destructor, but unfortunately, the MyClass destructor i not called if construction was not complete!
Avatar of gysbert1

ASKER

A few final comments

dhymes:  NO

The following class allocates memory when you call new and ilustrates my problem.
class myClass
{
  int i;
  myClass() {throw i;};
};


alexo:
Thanks for the quote from the spec! That lead me to the answer!

After more detailed analysis it turned out that it was not leaking in the way I thought!

The problem was that a member in my exception class was a STL string and that damn thing leaks !!!

It only leaks on the Borland compiler and not on Visual Age which I am also using so we have identified a compiler (or rather STL implementation) bug.


Here is my test code that leaked for reference:

#include <iostream>

  class tEX
  {
  public:
      std::string error;
      tEX(std::string msg) {error = msg;};
      tEX(const tEX& e) {error = e.error;};
  };

  class myClass
  {
  public:
     char buffer[1024];

     myClass() {throw tEX("error !!");};
  };

void main(void)
{
  myClass* p = NULL;
  int i = 0;

  while (i++ < 10000)
  {
     try
     {
        p = new myClass;
     }
     catch (...)   {}

     delete p;
  }
}