I want to explicitly destroy an object (call the destructor on it and all its fields), but it may happen that I still hold some pointers to the object in question. Thus, I don't want to yet free the memory; instead I would like to leave a sort of a flag "I am a destroyed object".
I came with an idea of the following approach:
class BaseClass { //all objects in question derive from this class
public:
BaseClass() : destroyed(false) {}
virtual ~BaseClass() {}
private:
bool destroyed;
public:
bool isDestroyed() { return destroyed; }
void destroy() {
this->~BaseClass(); //this will call the virtual destructor of a derivative class
new(this) BaseClass();
destroyed=true;
}
};
When destroy is called, I basically destroy the whatever object I had (perhaps a derivative one) and create a new "zombie" one in that very same place. As a result I hope to achieve:
Any other pointer ptr previously pointing to this object can still call ptr->isDestroyed() to verify its existence.
I am aware that if I don't check the flag of the zombie and try to access fields belonging to any derived object, bad things may happen
I am aware that the zombie object still consumes as much memory as the destroyed object (as it may be a derivative of BaseClass)
I still have to free memory of the destroyed object. I hope however, that calling delete is still correct?
Questions:
Are there any other problems which I should consider when using the above pattern?
Will calling delete on the zombie object correctly free whole memory consumed by the previous (normal) object?
While I appreciate your input on how to do it differently, and I may be inclined to do it your way - I would still like to understand all the risks that the above code poses.
You got some nasty comments to your question. Now I don't think they are deserved although there may be better ways to do what you want. I understand where you are coming from but actually you are using the destructor the same way you would use the reset function you refuse to write. Actually you gain nothing from calling a destructor since calling a distructor has nothing to do with actually deleting or resetting anything unless you actually write the code to do it within the destructor.
As to your question about the placement new:
As you may know already the placement new doesn't allocate any memory so calling it will just create the object in the same place. I understand that is exactly what you want but it's just not ncessary. Since you don't call delete on your object just destroy, you can set destroyed to true without initializing the class.
To sum it up:
If you use the destructor as a regular virtual function you gain nothing. Don't do it since you can get into trouble if a destructor is called twice
A call to a placement new will not allocate memory and just perform needless initialization. You can just set destroyed to true.
To do what you want to do correctly and gain the benefits of destructors, you should overload the new and delete operators of your classes and use the normal destruction mechanism. You can then opt not to release the memory but mark it as invalid or maybe release most of the memory but leave the pointer pointing to some flags.
EDIT
Following the comments I decided to sum up all the risks I see and the risks that others have pointed out:
Accessing invalid pointer in a multi-threaded environment: Using your method a class may be accessed after the destructor has run but before the destroyed flag is set (As to your question in one of the comments - shared_ptr is for most purposes thread safe)
Relaying on a behavior you don't totally control: Your method relies on the way destructors auto call the destructors of other members which are not dynamically allocated: This means that you still have to release dynamically allocates memory specifically, You have no control on how exactly this is implemented, You have no control on the order in which other destructors are called.
Relaying on a behavior you don't totally control (Point 2): You are relaying on the way a compiler implements the part of the destructor which calls other destructors you have no way in telling whether your code will be portable or even how will it handle calling it twice.
Destructors may be called twice: Depending on your implementation this may cause memory leaks or heap corruption unless you guard against releasing the same memory twice. You claim you guard against that case by calling the placement new - However in a multi-threading environment this is not guaranteed further more you assume that all memory allocations are done by the default constructor - depending on your specific implementation this may or may not be true.
You are going against the better judgment of everyone that answered your question or commented on it - You may be onto something genius but most probably you are just shooting yourself in the leg by limiting your implementation to a small subset of situations where it will work correctly. It is like when you use the wrong screwdriver you will eventually end up damaging the screw. In the same way using a language construct in a way it was not intended to be used may end up with a buggy program - Destructors are intended to be called from delete and from the code generated by the compiler to clear the stack. Using it directly is not wise.
And I repeat my suggestion - overload delete and new for what you want
There is a suggestion of using smart pointers. In fact - I am doing that, but my references are circular. I could use some fully-fledged garbage collectors, but since I know myself where (and when!) circle chains can be broken, I want to take advantage of that myself.
Then you can explicitly null-ify (reset if you are using shared_ptr) one of the circular smart pointers and break the cycle.
Alternatively, if you know where the cycles will be in advance, you should also be able to avoid them in advance using weak_ptr in place of some of the shared_ptrs.
--- EDIT ---
If an object referenced by weak pointers only would merely get flagged as "invalid" and release control over all its contained pointers (is this sentence clear?), I would be happy.
Then weak_ptr::expired should make you happy :)
As with everyone else, I recommend you should just use weak_ptr. But you asked why your approach doesn't work as well. There are some issue of elegant implementation and separation of concerns that your code walks all over, but I won't argue those. Instead, I'll just point out that your code is horribly not thread-safe.
Consider the following execution sequence of two threads of control:
// Thread One
if ( ! ptr -> isDestroyed() ) { // Step One
// ... interruption ...
ptr -> something(); // Step Three
And the other:
// Thread Two
ptr -> destroy(); // Step Two
By the time step 3 comes around, the pointer is no longer valid. Now it's possible to fix this by implementing lock() or similar, but now you've incurred the possibility of defects about not releasing locks. The reason that everyone is recommending weak_ptr is that this whole class of problems has been worked out both in the interface of the class and its implementations.
One issue remains. You seem to want a facility where you can kill an object at will. This is the tantamount to requiring that the only pointers to an object are weak ones, that no strong ones are present that would break when the object was manually deleted. (I'll stipulate that this isn't a bad idea, though I must say I don't know why it's not in your case.) You can get this by building on top of weak_ptr and shared_ptr. These classes are generic, so if you want to disallow shared_ptr access to BaseClass, then you can write a specialization for shared_ptr<BaseClass> that behaves differently. Hide one instance of shared_ptr<BaseClass> to prevent deletion and provide such pointers through a factory method under your control.
In this model the semantics of destroy() need attention. The first choice is whether you want synchronous or asynchronous operation. A synchronous destroy() would block until all external pointers are released and not allow the issuing of new ones. (I'll assume that copy constructors are already disabled on the pointer.) There are two kinds of asynchronous destroy(). The simpler of the two fails if there still exist external references. Calling unique() on the hidden shared_ptr() makes this an easy implementation. The more complicated one acts like an asynchronous I/O call, scheduling the destruction to happen at some point in the future, presumably as soon as all external references are gone. This function might be called mark_for_death() to reflect the semantics, since the object might or might not be destroyed at return time.
I would consider using one appropriate of the smart pointer patterns instead. Behavior of accessing a deleted object is still undefined and a 'zombie' flag won't really help. The memory that was associated with the object instance that was deleted could be immediately occupied by any other object created, thus accessing the zombie flag isn't an information you can trust.
IMHO the placement new operator
new(this) BaseClass();
used in your destroy() method won't really help. Depends a bit how this method is intended to be used. Instead of deleting derived objects or inside destructors of deleted objects. In the latter case the memory will be freed anyway.
UPDATE:
According to your edit, wouldn't it be better to use the shared pointer/weak pointer idiom to solve the occurrence of circular references. I would consider these as a design flaw otherwise.
Related
I am familiar with std::shared_ptr and std::weak_ptr and know how they work. However, I would like the std::shared_ptr to emit a callback, like a boost signal. This would allow std::weak_ptr, who still refer to the deleted object, to be cleaned up right in time.
Is there maybe already some smart pointer implementation, which will report the destruction?
Explanation
I think there might be a small design flaw in std::weak_ptrs, that can lead to false memory leaks. By "false memory leak" I mean an object, that is still accessible by the program, but whose reason of existence is not valid anymore. The difference to a true memory leak is, that the true memory leak is completely unknown by the program, while the false leak is just a part that wasn't cleaned up properly.
Another description can be found at codingwisdom.com
Use Watchers
One of the problems with freeing an object is that you may have done so while other things are still pointing at it. This introduces dangling pointers and crashes! To combat the evil of dangling pointers, I like to use a basic "watcher" system. This is not unlike the weak reference discussed above. The implementation is like this:
Create a base class "Watchable" that you derive from on objects that should broadcast when they're being deleted. The Watchable object keeps track of other objects pointing at it.
Create a "Watcher" smart pointer that, when assigned to, adds itself to the list of objects to be informed when its target goes away.
This basic technique will go a long way toward solving dangling pointer issues without sacrificing explicit control over when an object is to be destroyed.
Example
Let's say we implement the observer pattern using boost Boost Signals2. We have a class Observable, that contains one or more signals and another class Observer, that connects to Observable's signals.
What would happen to Observable's slots, when a observing Observer is deleted? When we do nothing, then the connection would point to nowhere and we would probably receive a segmentation fault, when emitting the signal.
To deal with this issue, boost's slots also offer a method track(const weak_ptr<void>& tracked_object). That means, if I call track and pass a weak_ptr to Observer, then the slot won't be called when the weak_ptr expired. Instead, it will be deleted from the signal.
Where is the problem? Let's we delete an Observer and never call a certain signal of Observable ever again. In this case, the tracked connection will also never be deleted. Next time we emit the signal it will be cleaned up. But we don't emit it. So the connection just stays there and wastes resources.
A solution would be: when owning shared_ptr should emit a signal when it is destroying it's object. This would allow other other objects to clean up right in time. Everything that has a weak_ptr to the deleted object might register a callback and false memory leaks could be avoided.
//
// create a C function that does some cleanup or reuse of the object
//
void RecycleFunction
(
MyClass * pObj
)
{
// do some cleanup with pObj
}
//
// when you create your object and assign it to a shared pointer register a cleanup function
//
std::shared_ptr<MyClass> myObj = std::shared_ptr<MyClass>( new MyClass,
RecycleFunction);
Once the last reference expires "RecyleFunction" is called with your object as parameter. I use this pattern to recycle objects and insert them back into a pool.
This would allow std::weak_ptr, who still refer to the deleted object,
to be cleaned up right in time.
Actually, they only hold weak references, which do not prevent the object from being destroyed. Holding weak_ptrs to an object does not prevent it's destruction or deletion in any fashion.
The quote you've given sounds to me like that guy just doesn't know which objects own which other objects, instead of having a proper ownership hierarchy where it's clearly defined how long everything lives.
As for boost::signals2, that's what a scoped_connection is for- i.e., you're doing it wrong.
The long and short is that there's nothing wrong with the tools in the Standard (except auto_ptr which is broken and bad and we have unique_ptr now). The problem is that you're not using them properly.
This seems like a rather trivial or at least common question, but I couldn't find a satisfying answer on google or on SO.
I'm not sure when I should implement a destructor for my class.
An obvious case is when the class wraps a connection to a file, and I want to make sure the connection is closed so I close it in the destructor.
But I want to know in general, how can I know if I should define a destructor. What guidelines are there that I can check to see if I should have a destructor in this class?
One such guideline I can think of, is if the class contains any member pointers. The default destructor would destory the pointers on deletion, but not the objects they're pointing at. So that should be the work of a user-defined destructor. E.g: (I'm a C++ newbie, so this code might not compile).
class MyContainer {
public:
MyContainer(int size) : data(new int[size]) { }
~MyContainer(){
delete [] data;
}
// .. stuff omitted
private:
int* data;
}
If I hadn't supplied that destructor, than destroying a MyContainer object would mean creating a leak, since all the data previously referenced by data wouldn't have been deleted.
But I have two questions:
1- Is this the only 'guideline'? I.e. define a destructor if the class has member pointers or if it's managing a resource? Or is there anything else?
2- Are there cases when I should not delete member pointers? What about references?
You need to define a destructor if the default destruction does not suffice. Of course, this just punts the question: what does the default destructor do? Well, it calls the destructors of each of the member variables, and that's it. If this is enough for you, you're good to go. If it's not, then you need to write a destructor.
The most common example is the case of allocating a pointer with new. A pointer (to any type) is a primitive, and the destructor just makes the pointer itself go away, without touching the pointed to memory. So the default destructor of a pointer does not have the right behavior for us (it will leak memory), hence we need a delete call in the destructor. Imagine now we change the raw pointer to a smart pointer. When the smart pointer is destroyed, it also calls the destructor of whatever its pointing to, and then frees the memory. So a smart pointer's destructor is sufficient.
By understanding the underlying reason behind the most common case, you can reason about less common cases. It's true that very often, if you're using smart pointers and std library containers, their destructors do the right thing and you don't need to write a destructor at all. But there are still exceptions.
Suppose you have a Logger class. This logger class is smart though, it buffers up a bunch of messages to Log, and then writes them out to a file only when the buffer reaches a certain size (it "flushes" the buffer). This can be more performant than just dumping everything to a file immediately. When the Logger is destroyed, you need to flush everything from the buffer regardless of whether it's full, so you'll probably want to write a destructor for it, even though its easy enough to implement Logger in terms of std::vector and std::string so that nothing leaks when its destroyed.
Edit: I didn't see question 2. The answer to question 2 is that you should not call delete if it is a non-owning pointer. In other words, if some other class or scope is solely responsible for cleaning up after this object, and you have the pointer "just to look", then do not call delete. The reason why is if you call delete and somebody else owns it, the pointer gets delete called on it twice:
struct A {
A(SomeObj * obj) : m_obj(obj){};
SomeObj * m_obj;
~A(){delete m_obj;};
}
SomeObj * obj = new SomeObj();
A a(obj);
delete obj; // bad!
In fact, arguably the guideline in c++11 is to NEVER call delete on a pointer. Why? Well, if you call delete on a pointer, it means you own it. And if you own it, there's no reason not to use a smart pointer, in particular unique_ptr is virtually the same speed and does this automatically, and is far more likely to be thread safe.
Further, furthermore (forgive me I'm getting really into this now), it's generally a bad idea to make non-owning views of objects (raw pointers or references) members of other objects. Why? Because, the object with the raw pointer may not have to worry about destroying the other object since it doesn't own it, but it has no way of knowing when it will be destroyed. The pointed to object could be destroyed while the object with the pointer is still alive:
struct A {
SomeObj * m_obj;
void func(){m_obj->doStuff();};
}
A a;
if(blah) {
SomeObj b;
a.m_obj = &b;
}
a.func() // bad!
Note that this only applies to member fields of objects. Passing a view of an object into a function (member or not) is safe, because the function is called in the enclosing scope of the object itself, so this is not an issue.
The harsh conclusion of all this is that unless you know what you're doing, you just shouldn't ever have raw pointers or references as member fields of objects.
Edit 2: I guess the overall conclusion (which is really nice!) is that in general, your classes should be written in such a way that they don't need destructors unless the destructors do something semantically meaningful. In my Logger example, the Logger has to be flushed, something important has to happen before destruction. You should not write (generally) classes that need to do trivial clean-up after their members, member variables should clean up after themselves.
A class needs a destructor when it "owns" a resource and is responsible for cleaning it up. The purpose of the destructor is not simply to make the class itself work properly, but to make the program as a whole work properly: If a resource needs to be cleaned up, something needs to do it, and so some object should take responsibility for the cleanup.
For instance, memory might need to be freed. A file handle might need to be closed. A network socket might need to be shut down. A graphics device might need to be released. These things will stay around if not explicitly destroyed, and so something needs to destroy them.
The purpose of a destructor is to tie a resource's lifetime to an object's, so that the resource goes away when the object goes away.
A Destructor is useful for when your classes contain Dynamically Allocated Memory. If your classes are simple and don't have 'DAM', then it's safe to not use a Destructor. In addition, read about the Rule Of Three. You should also add a copy constructor and an overloaded = operator if your class is going to have 'DAM'.
2) Do not worry about References. They work in a different way such as that it "Refers" to another variable (Which means they don't point to the memory).
I wrote a project using normal pointers and now I'm fed up with manual memory management.
What are the issues that one could anticipate during refactoring?
Until now, I already spent an hour replacing X* with shared_ptr<X> for types I want to automatically manage memory. Then I changed dynamic_cast to dynamic_pointer_cast. I still see many more errors (comparing with NULL, passing this to a function).
I know the question is a bit vague and subjective, but I think I can benefit from experience of someone who has already done this.
Are there some pitfalls?
Although it's easy to just use boost::shared_pointer everywhere, you should use the correct smart pointer as per ownership semantics.
In most cases, you will want to use std::unique_ptr by default, unless the ownership is shared among multiple object instances.
If you run into cyclical ownership problems, you can break up the cycles with boost::weak_ptr.
Also keep in mind that while passing shared_ptr's around, you should always pass them by const reference for performance reasons (avoids an atomic increment) unless you really want to confer ownership to a different entity.
Are there some pitfalls?
Yes, by murphy's law if you blindly replace every pointer with shared_ptr, it'll turn out that isn't what you wanted, and you'll spend next 6 months hunting bugs you introduced.
What are the issues that one could anticipate during refactoring?
Inefficient memory management, unused resources being stored longer than necessary, memory leaks (circular references), invalid reference counting (same pointer assigned to multiple different shared_pointers).
Do NOT blindly replace everything with shared_ptr. Carefully investigate program structure and make sure that shread_ptr is NEEDED and it represents EXACTLY what you want.
Also, make sure you use version control that supports easy branching (git or mercurial), so when you break something you can revert to previous state or run something similar to "git bisect" to locate problem.
obviously you need to replace X* with shared_ptr
Wrong. It depends on context. If you have a pointer that points into the middle of some array (say, pixel data manipulation), then you won't be able to replace it with shared_ptr (and you won't need to). You need to use shared_ptr only when you need to ensure automatic deallocation of object. Automatic deallocation of object isn't always what you want.
If you wish to stick with boost, you should consider if you want a boost::shared_ptr or a boost::scoped_ptr. A shared_ptr is a resource to be shared between classes, whereas a scoped_ptr sounds more like what you may want (at least in some places). A scoped_ptr will automatically delete the memory when it goes out of scope.
Be wary when passing a shared_ptr to a function. The general rule with shared_ptr is to pass by value so a copy is created. If you pass it by reference then the pointer's reference count will not be incremented. In this case, you might end up deleting a piece of memory that you wanted kept alive.
There is a case, however, when you might want to pass a shared_ptr by reference. That is, if you want the memory to be allocated inside a different function. In this case, just make sure that the caller still holds the pointer for the lifetime of the function it is calling.
void allocPtr( boost::shared_ptr< int >& ptrByRef )
{
ptrByRef.reset( new int );
*ptrByRef = 3;
}
int main()
{
boost::shared_ptr< int >& myPointer;
// I want a function to alloc the memory for this pointer.
allocPtr( myPointer ); // I must be careful that I still hold the pointer
// when the function terminates
std::cout << *ptrByRef << std::endl;
}
I'm listing the steps/issues involved. They worked for me, but I can't vouch that they are 100% correct
0) check if there could be cyclic shared pointers. If so, can this lead to memory leak? I my case, luckily, cycles need not be broken because if I had a cycle, the objects in the cycle are useful and should not be destroyed. use weak pointers to break cycles
1) you need to replace "most" X* with shared_ptr<X> . A shared_ptr is (only?) created immediately after every dynamic allocation of X . At all other times, it is copy constructed , or constructed with an empty pointer(to signal NULL) . To be safe (but a bit inefficient), pass these shared_ptrs only by reference . Anyways, it's likely that you never passed your pointers by reference to begin with => no additional change is required
2) you might have used dynamic_cast<X*>(y) at some places. replace that with
dynamic_pointer_cast<X>(y)
3) wherever you passed NULL(eg. to signal that a computation failed), pass an empty shared pointer.
4) remove all delete statements for the concerned types
5) make your base class B inherit from enable_shared_from_this<B>. Then wherever you passed this , pass, shared_from_this() . You might have to do static casting if the function expected a derived type . keep in mind that when you call shared_from_this(), some shared_ptr must already be owning this . In particular, don't call shared_from_this() in constructor of the class
I'm sure one could semi-automate this process to get a semantically equivalent but not necessarily very-efficient code. The programmer probably only needs to reason about cyclic reference(if any).
I used regexes a lot in many of these steps. It took about 3-4 hours. The code compiles and has executed correctly so far.
There is a tool that tries to automatically convert to smart pointers. I've never tried it. Here is a quote from the abstract of the following paper:
http://www.cs.rutgers.edu/~santosh.nagarakatte/papers/ironclad-oopsla2013.pdf
To enforce safety properties that are difficult to check statically,
Ironclad C++ applies dynamic checks via templated “smart
pointer” classes.
Using a semi-automatic refactoring tool, we have ported
nearly 50K lines of code to Ironclad C++
What is the advantage in de-allocating memory in reverse order to variables?
Consider this example:
Type1 Object1;
Type2 Object2(Object1);
Suppose that Object2 uses some internal resources of Object1 and is valid as long as Object1 is valid. For example, Object2s destructor accesses Object1's internal resource. If it weren't for the guarantee of reverse order of destruction, this would lead to problems.
It's not just about deallocating memory, it's about symmetry in a broader sense.
Each time you create an object you are creating a new context to work in. You "push" into these contexts as you need them and "pop" back again later -- symmetry is necessary.
It's a very powerful way of thinking when it comes to RAII and exception-safety, or proving correctness w.r.t. preconditions and postconditions (constructors establish invariants, destructors ought to assert() them, and in well-designed classes each method clearly preserves them).
IMHO, lack of this feature is Java's single biggest flaw. Consider objects whose constructors open file handles or mutexes or whatever -- Armen's answer brilliantly illustrates how this symmetry enforces some common-sense constraints (languages such as Java may let Object1 go out of scope before Object2 but Object2 keeps Object1 alive by reference counting) but there's a whole wealth of design issues that fall neatly into place when considered in terms of object lifetimes.
Lots of C++ gotchas explain themselves when you bear this in mind
why gotos can't cross initialisations
why you may be advised to have only one return in any function (this only applies to non-RAII languages such as C and Java)
why an exception is the only reasonable way for a constructor to fail, and likewise why destructors can never reasonably throw
why you shouldn't call virtual functions in a constructor
etc etc...
The guarantee of destruction order of local variables is to allow you to write (for example) code like this:
{
LockSession s(lock);
std::ofstream output("filename");
// write stuff to output
}
LockSession is a class that acquires the lock in its constructor and releases it in its destructor.
At the }, we know that the file handle will be closed (and flushed) before the lock is released, which is a very useful guarantee to have if there are other threads in the program that use the same lock to protect access of the same file.
Suppose that destruction order were not specified by the standard, then we'd have to worry about the possibility that this code would release the lock (allowing other threads to access the file), and only then set about flushing and closing it. Or to keep the guarantee we need, we'd have to write the code like this, instead:
{
LockSession s(lock);
{
std::ofstream output("filename");
// write stuff to output
} // closes output
} // releases lock
This example isn't perfect - flushing a file isn't guaranteed to actually succeed, so relying on an ofstream destructor to do it doesn't result in bullet-proof code in that respect. But even with that problem, we are at least guaranteed that we don't have the file open any more by the time we release the lock, and in general that's the sort of useful guarantee that destruction order can provide.
There are also other guarantees of destruction order in C++, for example that base class subobjects are destroyed after the derived class destructor has run, and that data members of an object are destroyed in reverse order of construction, also after the derived class destructor is run and before the base class subobjects. Each guarantee is there so that you can write code that relies in some way on the second thing still being there while the first thing is destroyed.
None of this has very much to do with the actual de-allocation of memory, it's much more about what the destructor does. Since you ask about de-allocation, though, there might be some cases where certain memory allocator implementations benefit from blocks being freed in reverse order of their allocation. It could make it a little bit easier for the allocator to reduce memory fragmentation by merging adjacent free blocks. You don't very often have to think about that, though, and anyway allocators that need to merge free blocks ought to be smart enough to do it whatever order they're allocated and freed.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is it safe to delete this?
I've been doing a little work on a class that's designed to act as a node in a linked list, and I figured I'd give the class its own deletion function as opposed to the managing class doing it. So basically it goes like this:
void Class::Delete() {
//Some cleanup code before deleting the object
delete this;
}
Now I've tested this and it appears to work fine, but I've had a problem in the past where objects have been in the middle of running code, been deleted, then obviously crashed the program by trying to use a no-longer-existing object.
Since "delete this" is right at the end of the function, it obviously exits the function and works fine, but is this sort of practice a bad idea at all? Could this ever blow up in my face if I'm not careful?
The FAQlite answers this quite well:
As long as you're careful, it's OK for
an object to commit suicide (delete
this).
Here's how I define "careful":
You must be absolutely 100% positive sure that this object was
allocated via new (not by new[], nor
by placement new, nor a local object
on the stack, nor a global, nor a
member of another object; but by plain
ordinary new).
You must be absolutely 100% positive sure that your member
function will be the last member
function invoked on this object.
You must be absolutely 100% positive sure that the rest of your
member function (after the delete this
line) doesn't touch any piece of this
object (including calling any other
member functions or touching any data
members).
You must be absolutely 100% positive sure that no one even touches
the this pointer itself after the
delete this line. In other words, you
must not examine it, compare it with
another pointer, compare it with NULL,
print it, cast it, do anything with
it.
Naturally the usual caveats apply in
cases where your this pointer is a
pointer to a base class when you don't
have a virtual destructor.
Basically, you need to take the same care as you do with deleteing any other pointer. However, there are more areas where things can go wrong with a member function committing suicide, compared with an explicitly-declared pointer.
Using delete this is a bad idea if one is not sure of the pitfalls & working around them.
Once you call delete this the object's destructor is going to be invoked and the dynamically allocated memory will be freed.
If the object was not allocated using new, it will be a Undefined behaviour.
If any of object's data members or virtual functions are accessed after delete this, the behaviour will be Undefined Behavior again.
Probably, It is best to avoid delete this given the above.
It's actually a frequent idiom, and about as safe as any delete. As
with all deletes, you have to ensure that no further code tries to
access the object, and you have to be sure that the object was
dynamically allocated. Typically, however, the latter is not a
problem, since the idiom is only relevant for objects which have a
lifetime determined by the semantics of the object, and such objects are
always allocated dynamically. Finding all of the pointers too the
object can be an issue (whether delete this is used or not); usually,
some form of the observer pattern will be used to notify all interested
parties that the object will cease to exist.
The idiomatic way of doing that in C++ is by putting the cleanup code in the destructor then let it be called automatically when you delete the object.
Class::~Class() {
do_cleanup();
}
void ManagingClass::deleteNode(Class* instance) {
delete instance; //here the destructor gets called and memory gets freed
}
There's a simple way of doing the same thing that doesn't involve undefined behavior:
void Class::Delete() {
//Some cleanup code before deleting the object
std::auto_ptr delete_me(this);
}