At what moment is an object exactly "created"? - c++

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

Related

The difference between a destructor and 'delete'

What is the difference between the destruction of an object and deletion in C++? In OOP, when an object goes out of the scope, the destructor is called, and when dynamically allocating memory we have to use the delete keyword inside the destructor. So what does it mean for an object to be destroyed or deleted?
A destructor is a special method for a class. It is called whenever an object goes out of scope, or someone calls it explicitly.
An example where an objects destructor is called, but no delete:
struct MyObject
{
MyObject() { std::cout << "default constructor"; }
~MyObject() { std::cout << "destructor"; }
void doWork() {};
}
int main()
{
{
MyObject object; //constructor is called and memory allocated for the object on the stack
object.doWork();
} //at the end of scope, the destructor of MyObject is called, and the stack memory is "released"
// object is not longer available and stack memory is free
}
An example when scope does not help you:
int main()
{
{
MyObject* object_ptr = new MyObject; //constructor is called and memory allocated on the heap. The pointer_ptr object
object_ptr->doWork();
} //at the end of scope the object_ptr is removed from the stack, but the destructor for the MyObject is not called!
// object_ptr is no longer available.
}
For the above example, we have an issue with the dynamically allocated memory. We explicitly call the destructor of the object we are pointing to by calling delete (and freeing the memory where MyObject is residing!):
int main()
{
{
MyObject* object_ptr = new MyObject; //constructor is called and memory allocated on the heap. The pointer_ptr object
object_ptr->doWork();
delete object_ptr; // destructor of MyObject is called and memory freed.
// object_ptr is still usable here, but it is pointing at an destroyed object, so don't use it! (unless you redirect it)
}
}
So delete is for managing the dynamic memory, but the destructor is a method of the class itself, which is always called when the object is getting freed from the memory (stack or heap). The destructor is called when freeing the memory for the object, so that if the object itself handles memory, is has time to release that memory. That's why smart pointers are good:
int main()
{
{
std::unique_ptr<MyObject> object_ptr = std::make_unique<MyObject>(); //constructor is called and memory allocated on the heap. The pointer_ptr object
object_ptr->doWork();
} //destructor for std::unique_ptr<MyObject> is called, which in turn calls delete on the object it is pointing at, which calls the destructor of that object!
}
There are multiple ways for memory allocation some of them are:
Automatic memory allocation :
In this case ,the variables defined inside a scope ,for example functions, are automatic allocated, and is usually stored on the stack. You have a limited control over the lifetime of this memory. E.g: automatic variables in a function are only there until the function finishes, then when going out of that scope, their destructors are called automatically i.e. you must not call delete to free the memory reserved for that object.
Dynamic memory allocation :
In this case , the variables defined inside a scope ,for example functions, are dynamically allocated. You control the size and the lifetime of these memory locations. If you don't free the reserved memory (delete it), the allocated memory is still valid and accessible, even though the function terminated (went out of scope) and in this case you'll have memory leakage, which may cause the program to crash. So the object should be delete explicitly which in turn will call the destructor for that object.
In the same way that a constructor is only part of the process of creating an object, invoking the destructor is just part of the process of destroying an object. It is a place where special clean-up code can go, like closing file handles or destroying other, indirectly-owned objects.
delete is the way you trigger the deletion of a dynamically allocated object. Other types of object are deleted automatically when they go out of scope. This keyword will clean up memory and more abstractly end the object's lifetime so that the compiler knows it doesn't conceptually "exist" any more.
You generally don't call the destructor manually, as it is usually insufficient for safely ending the lifetime of an object on its own. However, doing so is useful when you're taking super-fine-grained control over objects' existences, with (for example) placement new: then, it can be sufficient. But this is a special case.
When an object is destroyed it's destructor is called. A pointer to a dynamically allocated memory can be deleted, objects themselves can't be deleted (unless you think of a pointer as a kind of object).
Either of these actions can have knock on effects that cause the other action to happen (or more instances of the same action). For instance if you delete a pointer to an object, then the objects destructor will be called (if it has one) and it's destructor may cause other pointers to be deleted and other objects to be destroyed.
Basically destructor is about the death of objects and deletion is about the freeing of dynamically allocated memory, but the two actions are often intertwined.

c++ operator new how this works internally

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.

c++ Destructors, When and Where if Ever?

I can't help reading the bulk of forum posts on destructors and getting totally confused.
Some say to call the destructor (with delete) once for each call to new. Some say the destructor automatically gets called in a variety of circumstances i.e. when the pointer is reassigned, when the object goes out of scope. Some suggest the pointer going out of scope while being a return value where the object exists as a copy of its former self, (does this then need explicit destruction as it was originally created with a new?
There seems to be some suggestion that calling the same destructor more than once will corrupt memory so all delete calls should be partnered with *pointer = NULL; to avoid corruption. If not then some more advanced object management system would require implementing, or an iron-fisted rigour of ownership.
I can't seem to make any sense of discussions on calling sequence of destructors, i.e. does the call 1) originate at the base superclass and cascade down to the specific class, calling all virtualised destructors on the way, 2) originate at the instantiated class and move up to the superclass, or 3) originate at the particular cast the class has when it goes out of scope, then traverse both toward the instantiated and base class. Do cascading destructors
Ultimately I simply don't know strictly how or when to delete objects if ever, whether objects are responsible for deleting all objects they reference, how to cleanly handle a proper object-oriented deletion routine where an object is referenced multiple times, it's just a mess in my head. As you can see I can't really formulate a single solid question to ask, am really hoping someone can offer a clean and concise discussion of if not the single 'correct' approach, at least the industry best practice to object deletion.
There are 3 types of allocation for which destructors are called in different ways:
Automatic allocation
These objects reside in automatic memory (trivially, the stack):
int main()
{
A a;
//...
}
The destructor of a is automatically called when a goes out of scope (closing }).
Dynamic allocation
Objects reside in dynamic memory (the heap). They are allocated with new and in order for the dstructor to be called, you need to call delete:
int main()
{
A* a = new A;
delete a; //destructor called
}
In this case it was probably suggested you should assign NULL to a after the delete. There are two schools of thought regarding this (I personally wouldn't suggest it). The motivation would be that you could possibly call delete again on a and crash the program if you don't set it to NULL. Which is correct. But if you do call delete again, that's already a bug or something wrong in the logic, which shouldn't be masked by making the code appear to run correctly.
Static allocation
Objects reside in static memory. Regardless of where they are allocated, the destructor is automatically called when the program ends:
A a; //namespace scope
int main()
{
}
Here, As destructor is called when the program terminates, after main finishes.
The C++ language leaves memory management in the hand of the programmer, that is the reason for which you can find that level of confusion.
Repeating what Luchian Grigore said there are three main types of memory
automatic storage (stack)
dynamic storage (heap)
static storage
If you allocate an object in automatic storage the the object will be destroyed once the scope is terminated; for example
void foo() {
MyClass myclass_instance;
myclass_instance.doSomething();
}
in the above case when the function terminates myclass_instance is destroyed automatically.
If you instead allocate an object in the heap with new then it's your responsibility to call the destructor with delete.
In C++ also an object can have sub-objects. For example:
class MyBiggerClass {
MyClass x1;
MyClass x2;
...
};
those sub-objects are allocated in the same memory the containing object is allocated to
void foo() {
MyBiggerClass big_instance;
MyBiggerClass *p = new MyBiggerClass();
...
delete p;
}
in the above case the two sub-objects big_instance.x1 and big_instance.x2 will be allocated in automatic storage (stack), while p->x1 and p->x2 are allocated on the heap.
Note however that you don't need in this case to call delete p->x1; (compile error, p->x1 is not a pointer) or delete &(p->x1); (syntactically valid, but logical mistake because that it wasn't allocated explicitly on the heap, but as a sub-object of another object). Deleting the main object p is all that is needed.
Another complication is that an object may keep pointers to other objects instead of including them directly:
class MyOtherBigClass {
MyClass *px1;
MyClass *px2;
};
in this case it will be the constructor of MyOtherBigClass that will have to find the memory for the sub-objects and it will be ~MyOtherBigClass that will have to take care of destroying the sub-objects and freeing the memory.
In C++ destroying a raw pointer doesn't automatically destroy the content.
Base classes in simple cases can be seen just as hidden embedded sub-objects. I.e. it's like if an instance of the base object is embedded in the derived object.
class MyBaseClass {
...
};
class MyDerivedClass : MyBaseClass {
MyBaseClass __base__; // <== just for explanation of how it works: the base
// sub-object is already present, you don't
// need to declare it and it's a sub-object that
// has no name. In the C++ standard you can find
// this hidden sub-object referenced quite often.
...
};
This means that the destructor of the derived object doesn't need to call the destructor of the base object because this is taken care by the language automatically.
The case of virtual bases is more complex, but still the invocation of base destructors is automatic.
Given that memory management is in the control of the programmer there are a few strategies that have emerged to help programmers avoiding making a mess of intricate code that always ends up in object leaks or multiple destruction.
Plan carefully how you are going to handle lifetime of the instances. You cannot just leave this as an afterthought because it will be impossible to fix later. For every object instance it should be clear who creates and who destroys it.
When it's impossible to plan ahead of time when an object should be destroyed then use reference counters: for every object keep track how many pointers are referencing it and destroy the object once this number reaches zero. There are smart pointers that can take care of this for you.
Never keep around a pointer to an object that has already been destroyed.
Use containers that are classes designed explicitly to handle the lifetime of contained objects. Examples are std::vector or std::map.
If your code calls new, then it should call delete as well, yes. Except if you are using smart pointers (which will call delete for you when the pointer gets destroyed). Whenever possible, you should use smart pointers and use vector or string to avoid having to manually allocate memory using new - if you don't call new, you don't need to worry about making sure delete is called -> no memory leaks, and no problems with objects being destroyed at the wrong time, etc.
Calling delete multiple times for the same instance is definitely a bad idea.
If we have this:
class A
{
int *p;
public:
A() { p = new int[10]; }
~A() { delete [] p; }
};
class B
{
A a;
~B() { ... }
...
};
class C : public B
{
...
~C() { ... }
}
...
C *cp = new C;
....
delete cp;
then the destructor of C gets called by delete. The destructor of B is called by the C destructor, and the destructor of A gets called by the B destructor. This is automatic, and the compiler will "make sure this happens".
And if we don't call new:
...
{
C c;
...
} // Destructor for C gets called here (and B and A as describe above)

Is memory released when a destructor is called or when `delete` is called?

Assume you have an object of class Fool.
class Fool
{
int a,b,c;
double* array ;
//...
~Fool()
{
// destroys the array..
delete[] array ;
}
};
Fool *fool = new Fool() ;
Now, I know you shouldn't, but some fool calls the destructor on fool anyway. fool->~Fool();.
Does that mean fool's memory is freed, (ie a,b,c are invalid) or does that mean only whatever deallocations in ~Fool() function occur (ie the array is deleted only?)
So I guess my question is, is a destructor just another function that gets called when delete is called on an object, or does it do more?
If you write
fool->~Fool();
You end the object's lifetime, which invokes the destructor and reclaims the inner array array. The memory holding the object is not freed, however, which means that if you want to bring the object back to life using placement new:
new (fool) Fool;
you can do so.
According to the spec, reading or writing the values of the fields of fool after you explicitly invoke the destructor results in undefined behavior because the object's lifetime has ended, but the memory holding the object should still be allocated and you will need to free it by invoking operator delete:
fool->~Fool();
operator delete(fool);
The reason to use operator delete instead of just writing
delete fool;
is that the latter has undefined behavior, because fool's lifetime has already ended. Using the raw deallocation routine operator delete ensures that the memory is reclaimed without trying to do anything to end the object's lifetime.
Of course, if the memory for the object didn't come from new (perhaps it's stack-allocated, or perhaps you're using a custom allocator), then you shouldn't use operator delete to free it. If you did, you'd end up with undefined behavior (again!). This seems to be a recurring theme in this question. :-)
Hope this helps!
The destructor call does just that, it calls the destructor. Nothing more and nothing less. Allocation is separate from construction, and deallocation from destruction.
The typical sequence is this:
1. Allocate memory
2. Construct object
3. Destroy object (assuming no exception during construction)
4. Deallocate memory
In fact, if you run this manually, you will have to call the destructor yourself:
void * addr = ::operator new(sizeof(Fool));
Fool * fp = new (addr) Fool;
fp->~Fool();
::operator delete(addr);
The automatic way of writing this is of course Fool * fp = new Fool; delete fp;. The new expression invokes allocation and construction for you, and the delete expression calls the destructor and deallocates the memory.
Does that mean fool's memory is freed, (ie a,b,c are invalid) or does
that mean only whatever deallocations in ~Fool() function occur (ie
the array is deleted only?)
Fool::~Fool() has zero knowledge about whether the Fool instance is stored in dynamic storage (via new) or whether it is stored in automatic storage (i.e. stack objects). Since the object ceases to exist after the destructor is run, you can't assume that a, b, c and array will stay valid after the destructor exits.
However, because Fool::~Fool() knows nothing about how the Fool was allocated, calling the destructor directly on a new-allocated Fool will not free the underlying memory that backs the object.
You should not access a, b, and c after the destructor is called, even if it's an explicit destructor call. You never know what your compiler puts in your destructor that might make those values invalid.
However, the memory is not actually freed in the case of an explicit destructor call. This is by design; it allows an object constructed using placement new to be cleaned up.
Example:
char buf[sizeof (Fool)];
Fool* fool = new (buf) Fool; // fool points to buf
// ...
fool->~Fool();
The easiest place to see that the destructor is distinct from deallocation via delete is when the allocation is automatic in the first place:
{
Fool fool;
// ~Fool called on exit from block; nary a sign of new or delete
}
Note also the STL containers make full use of the explicit destructor call. For example, a std::vector<> treats storage and contained objects lifetime quite separately.

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

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;
}