I've spent the last 4 years in C# so I'm interested in current best practices and common design patterns in C++. Consider the following partial example:
class World
{
public:
void Add(Object *object);
void Remove(Object *object);
void Update();
}
class Fire : Object
{
public:
virtual void Update()
{
if(age > burnTime)
{
world.Remove(this);
delete this;
}
}
}
Here we have a world responsible for managing a set of objects and updating them regularly. Fire is an an object that might be added to the world under many different circumstances but typically by another object already in the world. Fire is the only object that knows when it has burned out so currently I have it deleting itself. The object that created the fire is likely no longer in existence or relevant.
Is this a sensible thing to do or is there a better design that would help clean up these objects?
There is nothing really wrong with objects deleting themselves in C++, most implementations of reference counting will use something similar. However, it is looked on as a slightly esoteric technique, and you will need to keep a really close eye on the ownership issues.
The delete will fail and may crash the program if the object was not allocated and constructed with new. This construct will prevent you from instantiating the class on the stack or statically. In your case, you appear to be using some kind of allocation scheme. If you stick to that, this might be safe. I certainly wouldn't do it, though.
I prefer a stricter ownership model. The world should own the objects in it and be responsible for cleaning them up. Either have world remove do that or have update (or another function) return a value that indicates that an object should be deleted.
I am also guessing that in this type of pattern, you are going to want to reference count your objects to avoid ending up with dangling pointers.
It certainly works for objects created by
new
and when the caller ofUpdate
is properly informed about that behavior. But i would avoid it. In your case, the ownership clearly is at the World, so i would make the world delete it. The object does not create itself, i think it should also not delete itself. Can be very surprising if you call a function "Update" on your object, but then suddenly that object is not existing anymore without World doing anything out of itself (apart from Removing it out of its list - but in another frame! The code calling Update on the object will not notice that).Some ideas on this
deleteObject(Object&)
maybe.shouldBeDeleted
function to each object which returns true if the object wishes to be deleted by its owner.I would prefer option 3. The world would call Update. And after that, it looks whether the object should be deleted, and can do so - or if it wishes, it remembers that fact by adding that object to a pending-removal list manually.
It's a pain in the ass when you can't be sure when and when not to be able to access functions and data of the object. For example, in wxWidgets, there is a wxThread class which can operate in two modes. One of these modes (called "detachable") is that if its main function returns (and the thread resources should be released), it deletes itself (to release the memory occupied by the wxThread object) instead of waiting for the owner of the thread object to call a wait or join function. However, this causes severe headache. You can never call any functions on it because it could have been terminated at any circumstances, and you can not have it created not with new. Quite some people told me they very much dislike that behavior of it.
The self deletion of reference counted object is smelling, imho. Let's compare:
Compare that with self-deleting refcounted objects:
I think the first is so much nicer, and i believe well designed reference counted objects do not do "delete this", because it increases coupling: The class using the reference counted data has to know and remember about that the data deletes itself as a side-effect of decrementing the reference-count. Note how "bmp" becomes possibly a dangling pointer in ~Bitmap's destructor. Arguably, not doing that "delete this" is much nicer here.
Answer to a similar question "What is the use of delete this"
I don't this there's anything inherently wrong with an object deleting itself, but another possible method would be to have the world be responsible for deleting objects as part of ::Remove (assuming all Removed objects were also deleted.)
You have made
Update
a virtual function, suggesting that derived classes may override the implementation ofUpdate
. This introduces two big risks.1.) An overridden implementation may remember to do a
World.Remove
, but may forget thedelete this
. The memory is leaked.2.) The overridden implementation calls the base-class
Update
, which does adelete this
, but then proceeds with more work, but with an invalid this-pointer.Consider this example: