Skip to main content
GameDev.net gamedev.net
🔒 Locked

Object self-deletion?

Started by Hoser Mar 10, 2003 at 5:50 PM 43 replies 1.5k views
Original Post
Hoser
Hoser
I had a small question regarding the deletion of objects allocated using the new operator. Are objects allowed to delete (delete operator here) themselves? For example, let''s say I have a pointer to an object, say pOBJECT, that was allocated as follows. pOBJECT = new OBJECT; Now, let''s say that OBJECT had a member function defined as follows: void DestroyOBJECT() { delete this; } My question comes down to this. Is the following sequence of code acceptable (ie code/syntax-wise...and from a memory deallocation perspective)? pOBJECT = new OBJECT; pOBJECT->DestroyOBJECT(); pOJBECT=NULL; Thanks, Mike
Zipster
Zipster
Sure. Just remember that after that context pointer is deleted, you can''t access any more member variables.
skillfreak
skillfreak
why not just

OBJECT::~OBJECT() {}

pOBJECT = new OBJECT;
delete pOBJECT;
pOJBECT=NULL;

owl
owl
quote:
Original post by skillfreak
why not just

OBJECT::~OBJECT() {}

pOBJECT = new OBJECT;
delete pOBJECT;
pOJBECT=NULL;




I guess he is trying to delete the object from inside like this->deleteObject(); and just gave a bad example. I don''t know if doing that is quite safe though, I never had to do it.
[size="2"]I like the Walrus best.
Shannon Barber
Shannon Barber
By placing the delete code inside of the object, you ensure that the correct delete implementation is invoked.

For instance, if the object is distributed in a dll, and code in the dll creates it, then code in the dll needs to destroy it. The main application and the dll do not neccessarily share the same heap.
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Hoser
Hoser
Thanks for the replies. Let me clarify why I need to do this. Basically, I''m creating an object that may have several references to it. I will be keeping track of the number of references by a count variable. The thing is, I want the object to free its own memory once the reference count reaches 0.
So, in my call to "DestroyOBJECT", I would actually be decrementing some variable...and calling "delete this" if the count reaches 0.
fizban75
fizban75
Basically, that''s a horrible design to have an object delete itself like that. There is absolutely no reason for an object to call "delete this." If it''s a reference counted object, then the reference count decrement should be in the destructor of the object and no where else.

Objects should not be allowed to dictate when they go out of scope. That is something that is dictated by the users of the object. When the object goes out of scope, it''s destructor will be called automatically, the reference count will be decremented and if it reaches zero, any dynamic memory will be freed. Simple as that.
owl
owl
Nice, some sort of garbage collector. What are you coding? If you don''t mind
[size="2"]I like the Walrus best.
SirHando
SirHando
There is nothing wrong with the design.

It fits in nicely with the Clone/Destroy model, commonly used with Visitor patterns.

Ciao
Xai
Xai
fizban has no clue what he''s talking about ...

YES an object is explicitly allowed to delete itself .. by calling "delete this" ... which will invoke it''s destructor .. so of course that code cannot be inside the destructor ... because the contructor is NOT ALLOWED TO FAIL, and may not ever be allowed to be called twice on the same object ... if the destructor can fail, your entire design is flawed ...

MANY design patters call for making the destructor private, and then having the object destroy itself when it is appropriate (aka garbage collecting, singletons, any ref counting, interface systems like COM, etc) ... there are so many valid reasons to do it, you almost cannot have a modern OO language that doesn''t allow it ... if you look in the book "Design Patterns" or "Pattern Hatching" or many articles in "C++ Report" there are many many examples of private contructors / destructors, and functions which call new and delete internally. The only messy part in the examples you gave, is the setting of the pointer to NULL afterward ... which is neccessary if you call delete as well .. so it''s not any better or worse either way ... althouh I have seen some systems that take a reference to the pointer in question, and set them to NULL for you ... so you CANNOT FORGOT or screw up ...
fizban75
fizban75
Xai, I never said an object can''t delete itself. What I said is that it shouldn''t ever need to. The deletion of an object should be handled by the user that creates it. The object itself should not determine when it is out of scope and no longer used.

The original poster''s code is completely flawed. For instance, if the code were written on Windows and the object was defined in a DLL, then if the executable that loaded the DLL called OBJECT *pObject = new OBJECT and then later called pObject->DestroyOBJECT(), because of the heap differences (if you statically linked to the CRT libs), you would get a heap violation because the delete would happen in the DLL even though the new happened in the executable. This is just one example.

My point is that object destruction should be handled by an "outside" force. That force could be the code that created the object in the first place with new, or it could be handed over to another object like an auto pointer or a garbage collecter that would make the call to delete.

So, in the end, I would consider it a bad design for an object to call delete on itself. It doesn''t know how it''s being used and therefore should not have the ability to determine when to call it''s own destructor.
SiCrane
SiCrane
fizban, how would you implement the semantics of IUnknown::Release() without self-deletion?
krez
krez
quote:
Original post by fizban75
The original poster''s code is completely flawed. For instance, if the code were written on Windows and the object was defined in a DLL, then if the executable that loaded the DLL called OBJECT *pObject = new OBJECT and then later called pObject->DestroyOBJECT(), because of the heap differences (if you statically linked to the CRT libs), you would get a heap violation because the delete would happen in the DLL even though the new happened in the executable. This is just one example.

one could make the constructor private or protected as well, so only a friend class (such as a factory class used to create and store the objects within a DLL) could create them in the proper heap.

i agree with you that it is a dangerous thing to play with if you are not careful, but it does have its uses.


*** 500 Error ***
--- krez ([email="krez_AT_optonline_DOT_net"]krez_AT_optonline_DOT_net[/email])
RamboBones
RamboBones
quote:
Original post by SiCrane
fizban, how would you implement the semantics of IUnknown::Release() without self-deletion?


I''m not fizban but anyway you''d do it simply like this
delete IUnkown;

ANYTHING you can do in a self delete or release function you can do in the deconstructor, or you can overload the delete operator if you only want the code to affect objects that are dynamically created.
fizban75
fizban75
SiCrane, you are correct, IUnknown::Release frees its memory if its reference count falls to zero. However, since I don't like the design of COM for the exact reason that it requires the user to manage the reference counting of the object, I will continue to say that I think objects calling delete on themselves is bad design. Of course you can do it if you so choose, but I'd prefer to see nothing of the sort in the code I write and work with.

Krez, in your case, the factory will be managing the life of the object, not the object itself, which I think is a great design.

My rule of thumb. If you call new to create an object, you should also call delete or hand it over to some other object who will call delete when going out of scope.

The problem with the given example from the original poster is that you could create the object on the stack:

OBJECT myobject;

What if you then pass it to a function that takes a pointer to OBJECT:

void f(OBJECT *pObject);
...
f(&myobject)

Then that function f() calls pObject->DestroyObject(). Oh shit, now you're in trouble because that's completely invalid. But the fact is that the compiler let it through, because it's valid from that standpoint.

This is the kind of danger that this design provokes. I'll stand by my original statement that this is bad design.

[edited by - fizban75 on March 10, 2003 11:16:13 PM]
Hoser
Hoser
I appreciate all the responses. I''ll explain what it is that I''m trying to do, and hence the reason for the original question.

I have an object that contains a set of data, call it DATAOBJ. DATAOBJ is dynamically created (> 10000 instances) within a class, call it CLASS1. Now I also have a couple other classes that will need to access a pointer to any of the DATAOBJ, say CLASS2 and CLASS3. My application is multithreaded. Things basically come down to this...

CLASS1 creates DATAOBJ dynamically with a call to the new operator.
CLASS2 or CLASS3 obtains a copy of the pointer to DATAOBJ at some point in time.

CLASS1 is finished using DATAOBJ...but CLASS2 and CLASS3 may still need access to it...so, I don''t want to call the delete operator from CLASS1.

My solution was as follows.

CLASS1 creates DATAOBJ, and DATAOBJ sets an internal reference count to 1.

Any time any other class wants a copy of a pointer to DATAOBJ, it makes a call to DATAOBJ->Reference()...which would increase the internal reference count by 1. When a class was finished with DATAOBJ, it would call DATAOBJ->Release().

The Release method would then decrease the internal reference count by 1. If the count is 0, the Release method would then free up the memory allocated to DATAOBJ with a call "delete this;". (hence the reason for my question).

Is there a different approach which will work much better?

owl
owl
quote:
Original post by fizban75
The problem with the given example from the original poster is that you could create the object on the stack:

OBJECT myobject;

What if you then pass it to a function that takes a pointer to OBJECT:

void f(OBJECT *pObject);
...
f(&myobject)

Then that function f() calls pObject->DestroyObject(). Oh shit, now you''re in trouble because that''s completely invalid. But the fact is that the compiler let it through, because it''s valid from that standpoint.

This is the kind of danger that this design provokes. I''ll stand by my original statement that this is bad design.


I think you got a point here. I think it''s quite dangerous to use it all the time.
[size="2"]I like the Walrus best.
Nypyren
Nypyren
Who here creates a refcounted object on the stack and passes it by reference rather than passing by value and using the copy ctor to add a reference? Raise your hand!

(doesn''t raise his hand)


The bottom line being: Any design is a bad design if you screw up. I believe that Hoser knows what he''s doing, and his self-deleting refcounted implementation is exactly how I would do it.
SiCrane
SiCrane
quote:
Original post by RamboBones
I''m not fizban but anyway you''d do it simply like this
delete IUnkown;

ANYTHING you can do in a self delete or release function you can do in the deconstructor, or you can overload the delete operator if you only want the code to affect objects that are dynamically created.


I really don''t think you understood the question. IUnknown is part of COM. Go look it up, and then try again.
TalonSnow
TalonSnow
In complicated game engines and systems, objects control objects exclusively, and users have nothign to do with it. In which case it usualy isnt the same object deleting itself, but a managing class. This is most commonly used in singleton, factory, controller classes working together. This relationship is by far one of the most arguable efficient and controlling memory allocation structures for games!
<=- Talon -=>

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.