• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 283
  • Last Modified:

"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 ?
0
gysbert1
Asked:
gysbert1
1 Solution
 
dhymesCommented:
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
0
 
alexoCommented:
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;
0
 
KangaRooCommented:
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.
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
alexoCommented:
Oops, my mistake.  See below for details.

My answer: a proper use of try/catch will automatically deallocate memory that was allocated when a constructor threw an exception.

The standard says:

--- quote ---

15.2 Constructors and destructors [except.ctor]

1) As control passes from a throw-expression to a handler, destructors are invoked for all automatic objects constructed since the try block was entered. The automatic objects are destroyed in the reverse order of the
completion of their construction.

2) An object that is partially constructed or partially destroyed will have destructors executed for all of its fully constructed subobjects, that is, for subobjects for which the constructor has completed execution and the destructor has not yet begun execution. Should a constructor for an element of an automatic array throw an exception, only the constructed elements of that array will be destroyed. If the object or array was allocated in a new-expression and the new-expression does not contain a new-placement, the deallocation function (3.7.3.2, 12.5) is called to free the storage occupied by the object; the deallocation function is chosen as specified in 5.3.4. If the object or array was allocated in a new-expression and the new-expression contains a new-placement, the storage occupied by the object is deallocated only if an appropriate placement operator delete is found, as specified in 5.3.4.

--- end quote ---

And in human terms: if a memory allocation fails due to an exception thrown from a constructor, the memory will be deallocated.  Therefore, the following code:

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

    X* p = 0;
    try { p = new X; }
    catch (...) {}

Will *not* cause a memory leak due to the thrown exception.

When tested, VC++ (with SP3) behaves correctly and deallocates the memory.
0
 
KangaRooCommented:
Looking at the question again, gysbert1, how do you know that there is memory that is not freed?
0
 
wildyCommented:
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.
0
 
alechkoCommented:
Hmm.. just thought of something, can't he call "delete this;" from constructor?
what will happen then ?
0
 
KangaRooCommented:
{
  MyClass m;
}
0
 
KangaRooCommented:
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!
0
 
gysbert1Author Commented:
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;
  }
}

0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now