C++:Handle Resources If Constructors May Throw Exceptions (Reference to Faq 17.4]

C++ : handle resources if constructors may throw exceptions (Reference to FAQ 17.4]

There is a similar question here that covers what your asking.

In this case, if the call to new fails, then the memory for the pointer is guaranteed to be freed. If the call succeeds, and the constructor throws after that, you will have a memory leak.

The destructor of the class will not be called, because the object was never fully constructed. There are two ways to fix this.

1)

Have exceptions fully managed in the constructor:

class Foo
{
public:
Foo()
try
{
p = new p;

throw /* something */;
}
catch (...)
{
delete p;

throw; //rethrow. no memory leak
}
private:
int *p;
};

2)

Or use a smart pointer. When a constructor is entered, all of its members have been constructed. And because when a constructor throws, and objects members have been constructed, they must be destructed. And a smart pointer fixes that:

class Foo
{
public:
Foo() :
p(new int)
{
throw /* something */;
}
private:
std::auto_ptr<int> p;
};

Is it ever not safe to throw an exception in a constructor?

Throwing exceptions from a constructor is a good thing. When something fails in a constructor, you have two options:

  • Maintain a "zombie" state, where the class exists but does nothing, or
  • Throw an exception.

And maintaining zombie classes can be quite a hassle, when the real answer should have been, "this failed, now what?".

According to the Standard at 3.6.2.4:

If construction or destruction of a non-local static object ends in throwing an uncaught exception, the result is to call terminate (18.6.3.3).

Where terminate refers to std::terminate.


Concerning your example, no. This is because you aren't using RAII concepts. When an exception is thrown, the stack will be unwound, which means all objects get their destructor's called as the code gets to the closest corresponding catch clause.

A pointer doesn't have a destructor. Let's make a simple test case:

#include <string>

int main(void)
{
try
{
std::string str = "Blah.";
int *pi = new int;

throw;

delete pi; // cannot be reached
}
catch(...)
{
}
}

Here, str will allocate memory, and copy "Blah." into it, and pi will be initialized to point to an integer in memory.

When an exception is thrown, stack-unwinding begins. It will first "call" the pointer's destructor (do nothing), then str's destructor, which will free the memory that was allocated to it.

If you use RAII concepts, you'd use a smart pointer:

#include <memory>
#include <string>

int main(void)
{
try
{
std::string s = "Blah.";
std::auto_ptr<int> pi(new int);

throw;

// no need to manually delete.
}
catch(...)
{
}
}

Here, pi's destructor will call delete and no memory will be leaked. This is why you should always wrap your pointers, and is the same reason we use std::vector rather than manually allocating, resizing, and freeing pointers. (Cleanliness and Safety)

Edit

I forgot to mention. You asked this:

I think I want to put an autoptr around P and call release on the autoptr after dostuff to prevent a memory leak, would that be correct?

I didn't state it explicitly, and only implied it above, but the answer is no. All you have to do is place it inside of auto_ptr and when the time comes, it will be deleted automatically. Releasing it manually defeats the purpose of placing it in a container in the first place.

I would also suggest you look at more advanced smart pointers, such as those in boost. An extraordinarily popular one is shared_ptr, which is reference counted, making it suitable for storage in containers and being copied around. (Unlike auto_ptr. Do not use auto_ptr in containers!)

Who deletes the memory allocated during a new operation which has exception in constructor?

You should refer to the similar questions here and here.
Basically if the constructor throws an exception you're safe that the memory of the object itself is freed again. Although, if other memory has been claimed during the constructor, you're on your own to have it freed before leaving the constructor with the exception.

For your question WHO deletes the memory the answer is the code behind the new-operator (which is generated by the compiler). If it recognizes an exception leaving the constructor it has to call all the destructors of the classes members (as those have already been constructed successfully prior calling the constructor code) and free their memory (could be done recursively together with destructor-calling, most probably by calling a proper delete on them) as well as free the memory allocated for this class itself. Then it has to rethrow the catched exception from the constructor to the caller of new.
Of course there may be more work which has to be done but I cannot pull out all the details from my head because they are up to each compiler's implementation.

When is it right for a constructor to throw an exception?

The constructor's job is to bring the object into a usable state. There are basically two schools of thought on this.

One group favors two-stage construction. The constructor merely brings the object into a sleeper state in which it refuses to do any work. There's an additional function that does the actual initialization.

I've never understood the reasoning behind this approach. I'm firmly in the group that supports one-stage construction, where the object is fully initialized and usable after construction.

One-stage constructors should throw if they fail to fully initialize the object. If the object cannot be initialized, it must not be allowed to exist, so the constructor must throw.

Example of memory leak in c++ (by use of exceptions)

class MyClass
{
public:
char* buffer;
MyClass(bool throwException)
{
buffer = new char[1024];
if(throwException)
throw std::runtime_error("MyClass::MyClass() failed");
}

~MyClass()
{
delete[] buffer;
}
};

int main()
{
// Memory leak, if an exception is thrown before a delete
MyClass* ptr = new MyClass(false);
throw std::runtime_error("<any error>");
delete ptr;
}

int main()
{
// Memory leak due to a missing call to MyClass()::~MyClass()
// in case MyClass()::MyClass() throws an exception.
MyClass instance = MyClass(true);
}

See also: C++ : handle resources if constructors may throw exceptions (Reference to FAQ 17.4]

What happens to the memory allocated by `new` if the constructor throws?

The memory will be automatically freed before the exception propagates.

This is essential, because a) the program never receives a pointer to free, and b) even if it did, it would have no portable way to actually free it since the memory never became an object that you can delete.

What's the best technique for exiting from a constructor on an error condition in C++

The best suggestion is probably what parashift says. But read my caution note below as well please.

See parashift FAQ 17.2

[17.2] How can I handle a constructor
that fails?

Throw an exception.

Constructors don't have a return type,
so it's not possible to use return
codes. The best way to signal
constructor failure is therefore to
throw an exception. If you don't have
the option of using exceptions, the
"least bad" work-around is to put the
object into a "zombie" state by
setting an internal status bit so the
object acts sort of like it's dead
even though it is technically still
alive.

The idea of a "zombie" object has a
lot of down-side. You need to add a
query ("inspector") member function to
check this "zombie" bit so users of
your class can find out if their
object is truly alive, or if it's a
zombie (i.e., a "living dead" object),
and just about every place you
construct one of your objects
(including within a larger object or
an array of objects) you need to check
that status flag via an if statement.
You'll also want to add an if to your
other member functions: if the object
is a zombie, do a no-op or perhaps
something more obnoxious.

In practice the "zombie" thing gets
pretty ugly. Certainly you should
prefer exceptions over zombie objects,
but if you do not have the option of
using exceptions, zombie objects might
be the "least bad" alternative.


A word of caution with throwing exceptions in a constructor:

Be very careful though because if an exception is thrown in a constructor, the class's destructor is not called. So you need to be careful about destructing objects that you already constructed before the exception is thrown. The same warnings apply to exception handling in general, but it is maybe a little less obvious when dealing with a constructor.

class B
{
public:
B()
{

}

virtual ~B()
{
//called after D's constructor's exception is called
}
};

class D : public B
{
public:
D()
{
p = new char[1024];
throw std::exception("test");
}

~D()
{
delete[] p;
//never called, so p causes a memory leak
}

char *p;
};

int main(int argc, char **argv)
{

B *p;
try
{
p = new D();
}
catch(...)
{

}

return 0;
}

Protected/Private constructors with CreateInstance method:

Another way around this is to make your constructor private or protected and make a CreateInstance method that can return errors.



Related Topics



Leave a reply



Submit