Re: Exception in Constructor
Am Sonntag, 16. September 2012 09:45:32 UTC+2 schrieb Henry:
[..]
http://www.parashift.com/c++-faq/ctors-can-throw.html It says, "if
a constructor finishes by throwing an exception, the memory
associated with the object itself is cleaned up ? there is no
memory leak".
However, as I know (and I tested), when an exception is thrown
inside a constructor, the destructor won't be called.
[..]
It doesn't seems to me that "if a constructor finishes by throwing
an exception, the memory associated with the object itself is
cleaned up ? there is no memory leak" is true.
On 9/17/12 2:25 AM, MiB wrote:
The statement from parashift.com is partly true, partly misleading
at best. The destructor is not called and parashift does not claim
so. Your observed behavior is what should happen.
The memory occupied by the object itself is released, so in this
regard parashift is right, too. - If this is not what you observe,
its a compiler bug IMHO.
However, there still is a memory hole, and this is where the site is
making too bold a statement. Allocations made by "new" in the
constructor are not tracked and there is no way to release it
lacking a Java/.NET like garbage collected memory model.
Huh? What does Garbage Collection have to do with this? The example
you have provided below deals pretty well with dynamically allocated
memory inside an exception-safe constructor.
A destructor call would not help since it got presented a halfway
constructed object only. It would pose a problem how to handle a
non-zero pointer member - is it non-zero because an allocation was
executed successfully or because it was not yet zeroed out?
External resource allocation may be even more difficult if you
cannot check for success if the return value is not yet stored by
the allocating routine (was the file opened or not before the
exception?).
If there is a chance code in a constructor with dynamic allocation
generates an exception, I recommend to catch any inside the
constructor itself individually and releasing all such resources
before re-throwing the exception.
E.g:
class A {
private:
char* cstr1;
char* cstr2;
char* cstr3;
public:
A() {
cstr1 = new char[1000]; // no need to catch here,
// no cleanup on fail
try {
cstr2 = new char[1000000]; // may fail
}
catch ( std::bad_alloc ) {
delete cstr1;
throw;
}
try {
cstr3 = new char[1000000]; // may fail
}
catch ( std::bad_alloc ) {
delete cstr1;
delete cstr2;
throw;
}
}
};
I prefer this over nested try..catch even if it means (minor) code
duplication. The point is to leave behind an object that only needs
to have its own memory released on exception.
The C++ way of doing this would be:
#include <vector>
class A
{
private:
std::vector<char> cstr1;
std::vector<char> cstr2;
std::vector<char> cstr3;
public:
A ()
{
// Phase (I): Allocation of
// Ressources.
//
// These allocations may throw
// std::bad_alloc, but we don't
// don't have to worry about
// unreleased memory since these
// variables will be cleaned up
// when an exception is thrown.
std::vector<char> temp_cstr1;
temp_cstr1.reserve(1000);
std::vector<char> temp_cstr2;
temp_cstr2.reserve(1000000);
std::vector<char> temp_cstr3;
temp_cstr3.reserve(1000000);
// Phase (II): Transfer of
// Ownership of
// Ressources.
//
// The following swaps are
// guaranteed not to throw,
// so the constructor will
// finish successfully once
// it reaches these lines.
cstr1.swap(temp_cstr1);
cstr2.swap(temp_cstr2);
cstr3.swap(temp_cstr3);
}
};
@Henry: If you are interested in exception-safe coding, I'd recommend
Herb Sutter's "Exceptional C++". This is a must have for serious C++
programmers.
Regards,
Stuart
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]