I was debating with some colleagues about what happens when you throw an exception in a dynamically allocated class. I know that malloc gets called, and then the constructor of the class. The constructor never returns, so what happens to the malloc?
Consider the following example:
class B
{
public:
B()
{
cout << "B::B()" << endl;
throw "B::exception";
}
~B()
{
cout << "B::~B()" << endl;
}
};
void main()
{
B *o = 0;
try
{
o = new B;
}
catch(const char *)
{
cout << "ouch!" << endl;
}
}
What happens to the malloced memory o, does it leak? Does the CRT catch the exception of the constructor and deallocate the memory?
Cheers!
Rich
A call to
new B();
resolves in two things:
allocating with an operator new() (either the global one or a class specific one, potentially a placement one with the syntax new (xxx) B())
calling the constructor.
If the constructor throw, the corresponding operator delete is called. The case where the corresponding delete is a placement one is the only case where a placement delete operator is called without the syntax ::operator delete(). delete x; or delete[] x; don't call the placement delete operators and there is no similar syntax to placement new to call them.
Note that while the destructor of B will not be called, already constructed subobjects (members or B and base classes of B) will be destructed before the call to operator delete. The constructor which isn't called is the one for B.
When an exception is thrown from the constructor, the memory allocated by new is released, but the destructor of class B is not called.
In this case, your object, o, does not actually get constructed, and the memory allocated by new is freed. As such, the destructor does not get called. So you do NOT need to call:
delete o;
An interesting design pattern is RAII -- Resource Acquisition Is Initialization. In this pattern, you use a constructor to encapsulate the acquisition of a resource, and release the resource in the destructor. If the resource can not be acquired, you throw in the constructor -- much like your example. Thus if you have a valid object, you have the resource.
If the object is constructed, then you have successfully acquired the resource. This means that for the life of the object, you own the resource. When the object is deleted, the resource is released. If the object is never constructed, then you never acquired the resource. See wikipedia:
http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
From the C++ 2003 Standard 5.3.4/17 - New:
If any part of the object initialization described above terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression. If no unambiguous matching deallocation function can be found, propagating the exception does not cause the object’s memory to be freed. [Note: This is appropriate when the called allocation function does not allocate memory; otherwise, it is likely to result in a memory leak. ]
So there may or may not be a leak - it depends on whether an appropriate deallocator can be found (which is normally the case, unless operator new/delete have been overridden).In the case where there's a suitable deallocator, the compiler is responsible for wiring in a call to it if the constructor throws.
Note that this is more or less unrelated to what happens to resources acquired in the constructor, which is what my first attempt at an answer discussed - and is a question that is discussed in many FAQs, articles, and postings.
Related
For example I have a simple code:
class B
{
};
class A
{
B b;
public:
A()
{
throw 1;
}
};
int main()
{
A* a = 0;
try
{
a = new A;
}
catch (int)
{
}
}
Constructor A throws exception, then destructor will not be called. But destructor for B will be called. Memory in the heap will not be allocated. My question how this works internally? What will be first: constructing A or allocating memory in the heap? So, if allocating is the first, how deallocating will be handled if there are exception? Othervise, if constructing A is the first, how it's copiing to the heap?
The memory is allocated.
The constructor of A is called.
The constructor of A calls the constructor of B.
The constructor of A throws.
As a part of the standard exception handling procedure, the destructor of B is called (RAII at work).
The stack unwinds to the caller (main).
The memory is deallocated (because the object wasn't constructed successfully).
The destructor of A isn't called because the object was not fully constructed. However, the members which were fully constructed are still destroyed.
The memory is deallocated automatically in pretty much the same way as local variables are destroyed when the control leaves the block. If you're familiar with Java and/or C#, think of it as an invisible try-finally construct. Or a series of such constructs.
What will be first: constructing A or allocating memory in the heap?
Unless there's memory, there's no space in which the object can be constructed. Memory allocation always goes first; then the code proceeds with initialization. This applies to all kinds of memory allocations, not only of the dynamic variety, because constructors need to have a valid address of this before they start initializing the object.
If allocating is the first, how deallocating will be handled if there are exception?
The compiler emits special code that handles the "magic" here. This code will run destructors for all base classes, and for members, such as B, that have been fully constructed by the time the code entered A's constructor.
Why C++ hasn't placement delete that directly corresponds to the placement new, i.e. calls the destructor and calls appropriate placement delete operator?
For example:
MyType *p = new(arena) MyType;
...
//current technique
p->~MyType();
operator delete(p, arena);
//proposed technique
delete(arena) p;
operator delete is unique in being a non-member or static member function that is dynamically dispatched. A type with a virtual destructor performs the call to its own delete from the most derived destructor.
struct abc {
virtual ~abc() = 0;
};
struct d : abc {
operator delete() { std::cout << "goodbye\n"; }
};
int main() {
abc *p = new d;
delete p;
}
(Run this example.)
For this to work with placement delete, the destructor would have to somehow pass the additional arguments to operator delete.
Solution 1: Pass the arguments through the virtual function. This requires a separate virtual destructor for every static member and global operator delete overload with different arguments.
Solution 2: Let the virtual destructor return a function pointer to the caller specifying what operator delete should be called. But if the destructor does lookup, this hits the same problem of requiring multiple virtual function definitions as #1. Some kind of abstract overload set would have to be created, which the caller would resolve.
You have a perfectly good point, and it would be a nice addition to the language. Retrofitting it into the existing semantics of delete is probably even possible, in theory. But most of the time we don't use the full functionality of delete and it suffices to use a pseudo-destructor call followed by something like arena.release(p).
Probably because there was syntax for explicitly calling a destructor without deallocation (exactly as in your question), but no syntax for explicit construction in raw memory?
Actually there is a placement delete which is called by the implementation for an object that was "allocated" using placement new if the constructor threw an exception.
From Wikipedia.
The placement delete functions are called from placement new expressions. In particular, they are called if the constructor of the object throws an exception. In such a circumstance, in order to ensure that the program does not incur a memory leak, the placement delete functions are called.
The whole point of placement new is to separate object creation from its memory management. So it makes no sense to tie it back during object destruction.
If memory for your objects is from heap and you want same lifetime for objects and their memory just use operator new and operator delete, maybe overriding them if you want any special behavior.
Placement new is good for example in vector, which keeps a large chunk of raw memory and creates and destroys object inside of it, but without releasing memory.
Consider the following class:
struct A
{
A(){ std::cout << "A()" << std::endl; throw std::exception(); }
~A(){ std::cout << "~A()" << std::endl; }
};
A a;
int main(){ }
DEMO
The Standard promised that the appropriate deallocation function will be called N4296::5.3.4/20 [expr.new]:
If any part of the object initialization described above78 terminates
by throwing an exception, storage has been obtained for the object,
and a suitable deallocation function can be found, the deallocation
function is called to free the memory in which the object was being
constructed,
But what about destructor? In that example it was no called. So, did we get UB?
Destructors are called for all successfully initialized objects.
Otherwise there would have had to be default zero-initialization (some overhead) in order to be able to assume anything in a destructor.
The A object whose constructor throws, is not successfully initialized. So its destructor is not executed. However, if it had any class type sub-objects (base class sub-objects, data members) that had been successfully initialized prior to the exception, then destructors would be called for these.
And no, throwing from a constructor is not UB.
On the contrary it's the common way of signalling construction failure, and it ensures that the caller will either have a successfully initialized and presumably useable object, or else (just) an exception.
History. Originally C++ didn't have exceptions. Construction failure was then signalled by assigning 0 to this. I can't recall how that interacted with allocation, but presumably the same way that an exception now does, namely a guaranteed deallocation. But with this scheme you could only fail construction for dynamically allocated objects…
Destructors are not same as deallocators. Whenever a variable goes out of scope the object referenced to the variable is deleted. In the problem you have given the object is a global variable, so it will be deleted when the program terminates.
Let's say we have some class with a constructor:
class MyClass
{
public:
MyClass()
{
//our code goes here
throw "OMG";//well, some code that throws an exception
}
};
Now, when an exception occurs, stack unwinding is being performed. I also know that if the exception is thrown from the constructor, the corresponding object's destructor will not be called, because the object was never completely "created" in the first place.
I'm a little confused by this. To me that implies that the object is considered "created" only when the constructor finishes. But obviously, all the memory is allocated at some place before (or right after) the constructor is called, because we can manipulate the object's members inside the constructor.
So when exactly is the object created in memory, and what happens to the memory of an object that caused the exception?
The memory is allocated before the body of the constructor.
If a constructor fails, the automatically allocated memory is freed.
And the accent of "automatically allocated" is important - if you have dynamically allocated memory in the constructor and the constructor fails (for example, you may have used new before throw "OMG"), this memory will leak.
That's because - you have allocated this memory, you need to free it.
You're right, that the destructor is not called, but the destructor is not the one, which frees the memory, allocated for the auto members of a class.
It's used (basically) to free memory, allocated by the user (in the constructor or somewhere else).
In other words, allocating memory for an object is different from the object's construction.
Another example - if you create an object dynamically, like:
MyObj* = new MyObj;
this will:
call operator new
then call the constructor of MyObj
See, both things are different.
Memory allocation and object construction are two separate things in C++. The compiler just makes sure that when thay're invoked together (which is the case with the regular - i.e., non-placement - new operator) and construction fails, the allocation is reverted.
Also, when the class has sub-objects (base classes and/or fields), the compiler invokes their constructors in a fixed order and makes sure than when one of them throws, the already-constructed sub-objects are disposed of properly (i.e., have their destructors called).
The memory of the object is freed, but the destructor is not called (hence e.g. dynamically allocated pointers created within the constructor are not freed if you do not handle the exception in the constructor correctly). In C++11 the spec says that the destructor is called if and only if one constructor has completed entirely (relevant since a constructor can refer to another constructor).
Example (memory allocated by new int () is not freed):
struct Broken {
int * i;
Broken () {
i = new int {5};
OperationCausingException ();
}
~Broken {
delete i;
}
}
try {
Broken * b = new Broken {};
} catch (...) {
}
// memory leak: *b is freed, but b->i still exists
I really can't believe I couldn't find a clear answer to this...
How do you free the memory allocated after a C++ class constructor throws an exception, in the case where it's initialised using the new operator. E.g.:
class Blah
{
public:
Blah()
{
throw "oops";
}
};
void main()
{
Blah* b = NULL;
try
{
b = new Blah();
}
catch (...)
{
// What now?
}
}
When I tried this out, b is NULL in the catch block (which makes sense).
When debugging, I noticed that the conrol enters the memory allocation routine BEFORE it hits the constructor.
This on the MSDN website seems to confirm this:
When new is used to allocate memory
for a C++ class object, the object's
constructor is called after the memory
is allocated.
So, bearing in mind that the local variable b is never assigned (i.e. is NULL in the catch block) how do you delete the allocated memory?
It would also be nice to get a cross platform answer on this. i.e., what does the C++ spec say?
CLARIFICATION: I'm not talking about the case where the class has allocated memory itself in the c'tor and then throws. I appreciate that in those cases the d'tor won't be called. I'm talking about the memory used to allocate THE object (Blah in my case).
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.
If an object cannot complete destruction because the constructor throws an exception, the first thing to happen (this happens as part of the constructor's special handling) is that all member variables to have been constructed are destroyed - if an exception is thrown in the initializer list, this means that only elements for which the initializer has completed are destroyed.
Then, if the object was being allocated with new, the appropriate deallocation function (operator delete) is called with the same additional arguments that were passed to operator new. For instance, new (std::nothrow) SomethingThatThrows() will allocate memory with operator new (size_of_ob, nothrow), attempt to construct SomethingThatThrows, destroy any members that were successfully constructed, then call operator delete (ptr_to_obj, nothrow) when an exception is propagated - it won't leak memory.
What you have to be careful is allocating several objects in succession - if one of the later ones throws, the previous ones will not be automatically be deallocated. The best way around this is with smart pointers, because as local objects their destructors will be called during stack unwinding, and their destructors will properly deallocate memory.
If the Constructor throws the memory allocated for the object is auto-magically returned to the system.
Note the destructor of the class that threw will not be called.
But the destructor of any base class (where the base constructor has completed) will also be called.
Note:
As most other people have noted members may need some clean up.
Members that have been fully initialized will have their destructors called, but if you have any RAW pointer members that you own (ie delete in the destructor) you will have to do some clean up before you do the throw (another reason not to use owned RAW pointers in your class).
#include <iostream>
class Base
{
public:
Base() {std::cout << "Create Base\n";}
~Base() {std::cout << "Destroy Base\n";}
};
class Deriv: public Base
{
public:
Deriv(int x) {std::cout << "Create Deriv\n";if (x > 0) throw int(x);}
~Deriv() {std::cout << "Destroy Deriv\n";}
};
int main()
{
try
{
{
Deriv d0(0); // All constructors/Destructors called.
}
{
Deriv d1(1); // Base constructor and destructor called.
// Derived constructor called (not destructor)
}
}
catch(...)
{
throw;
// Also note here.
// If an exception escapes main it is implementation defined
// whether the stack is unwound. By catching in main() you force
// the stack to unwind to this point. If you can't handle re-throw
// so the system exception handling can provide the appropriate
// error handling (such as user messages).
}
}
From the C++ 2003 Standard 5.3.4/17 - New:
If any part of the object initialization described above terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression. If no unambiguous matching deallocation function can be found, propagating the exception does not cause the object’s memory to be freed. [Note: This is appropriate when the called allocation function does not allocate memory; otherwise, it is likely to result in a memory leak. ]
So there may or may not be a leak - it depends on whether an appropriate deallocator can be found (which is normally the case, unless operator new/delete have been overridden).In the case where there's a suitable deallocator, the compiler is responsible for wiring in a call to it if the constructor throws.
Note that this is more or less unrelated to what happens to resources acquired in the constructor, which is what my first attempt at an answer discussed - and is a question that is discussed in many FAQs, articles, and postings.
The long and short of it is that if you haven't made any allocations of other entities in you object(as in your example) then the memory that was allocated will be deleted automatically. However, any new statements(or anything else that directly manages memory) needs to be handled in a catch statement in the constructor, Otherwise the object is deleted without deleting it's subsequent allocations and you, my friend, have a leak.
Quoted from C++ FAQ (parashift.com):
[17.4] How should I handle resources if my constructors may throw
exceptions?
Every data member inside your object should clean up its own mess.
If a constructor throws an exception, the object's destructor is not
run. If your object has already done something that needs to be undone
(such as allocating some memory, opening a file, or locking a
semaphore), this "stuff that needs to be undone" must be remembered
by a data member inside the object.
For example, rather than allocating memory into a raw Fred* data
member, put the allocated memory into a "smart pointer" member object,
and the destructor of this smart pointer will delete the Fred
object when the smart pointer dies. The template std::auto_ptr is an
example of such as "smart pointer." You can also write your own
reference counting smart pointer. You can also use smart pointers
to "point" to disk records or objects on other machines.
By the way, if you think your Fred class is going to be allocated
into a smart pointer, be nice to your users and create a typedef
within your Fred class:
#include <memory>
class Fred {
public:
typedef std::auto_ptr<Fred> Ptr;
...
};
That typedef simplifies the syntax of all the code that uses your
objects: your users can say Fred::Ptr instead of
std::auto_ptr<Fred>:
#include "Fred.h"
void f(std::auto_ptr<Fred> p); // explicit but verbose
void f(Fred::Ptr p); // simpler
void g()
{
std::auto_ptr<Fred> p1( new Fred() ); // explicit but verbose
Fred::Ptr p2( new Fred() ); // simpler
...
}
The problem described is as old as the road to Rome, to use a Dutch saying. I have worked out the problem and a memory allocation for an object that might throw an exception looks as follows:
try
{
std::string *l_string =
(_heap_cleanup_tpl<std::string>(&l_string),
new std::string(0xf0000000, ' '));
delete l_string;
}
catch(std::exception &)
{
}
Before the actual call to the new-operator, a nameless (temporary) object is created, which receives the address of the allocated memory through a user-defined new-operator (see the rest of this answer). In case of normal programme execution, the temporary object passes the result of the new-operator (the newly created and fully constructed object, in our case a very very very long string) to the variable l_string. In case of an exception, the value is not passed on, but the destructor of the temporary object deletes the memory (without ofcourse calling the destructor of the main object).
It is a bit fuzzy way of dealing with the issue, but it works. Problems may arise because this solution requires a user-defined new-operator and a user-defined delete-operator to go allong with it. The user-defined new/delete-operators would have to call the C++-standard library's implementation of new/delete-operators, but I have left that out for briefity and relied on malloc() and free() instead.
It is not the final answer, but I think it is worth working this one out.
PS: There was an 'undocumented' feature in the code below, so I have made an improvement.
The code for the temporary object is as follows:
class _heap_cleanup_helper
{
public:
_heap_cleanup_helper(void **p_heap_block) :
m_heap_block(p_heap_block),
m_previous(m_last),
m_guard_block(NULL)
{
*m_heap_block = NULL;
m_last = this;
}
~_heap_cleanup_helper()
{
if (*m_heap_block == NULL) operator delete(m_guard_block);
m_last = m_previous;
}
void **m_heap_block, *m_guard_block;
_heap_cleanup_helper *m_previous;
static _heap_cleanup_helper *m_last;
};
_heap_cleanup_helper *_heap_cleanup_helper::m_last;
template <typename p_alloc_type>
class _heap_cleanup_tpl : public _heap_cleanup_helper
{
public:
_heap_cleanup_tpl(p_alloc_type **p_heap_block) :
_heap_cleanup_helper((void **)p_heap_block)
{
}
};
The user-defined new-operator is as follows:
void *operator new (size_t p_cbytes)
{
void *l_retval = malloc(p_cbytes);
if (
l_retval != NULL &&
*_heap_cleanup_helper::m_last->m_heap_block == NULL &&
_heap_cleanup_helper::m_last->m_guard_block == NULL
)
{
_heap_cleanup_helper::m_last->m_guard_block = l_retval;
}
if (p_cbytes != 0 && l_retval == NULL) throw std::bad_alloc();
return l_retval;
}
void operator delete(void *p_buffer)
{
if (p_buffer != NULL) free(p_buffer);
}
I think it's kind of wierd for a constructor to raise an exception.
Could you have a return value and test it in your main?
class Blah
{
public:
Blah()
{
if Error
{
this.Error = "oops";
}
}
};
void main()
{
Blah* b = NULL;
b = new Blah();
if (b.Error == "oops")
{
delete (b);
b = NULL;
}