Archived

This topic is now archived and is closed to further replies.

Can an object delete itself?

This topic is 5586 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''m working on a class that is referance counted. Whenever something wants to referance the object they call object->AddRef(); and when done with it they call object->ReleaseRef(); The thing is that the way it is setup now, I have to make the last person holding a referance to delete it. The code becomes like this: if (object->ReleaseRef()) // returns true if this is the last ref { delete object; } A little intricate and convoluted. I want ReleaseRef to delete itself if there are no more referances, but I don''t know how to do this. Anyone have ideas?

Share this post


Link to post
Share on other sites
Yes, an object can delete itself like so...

void Object::ReleaseRef()
{
m_refCount--;
if (m_refCount == 0)
delete this;
}

I''ve seen this technique employed in a number of COM examples. Just make sure you don''t continue to use the object after it has deleted itself.

Share this post


Link to post
Share on other sites
There''s already a thread on this subject in the forum archive, and there''s a detailed response in the C++ FAQ Lite(make a search for ''delete this'').

In a nutshell, it''s OK, but you have to be careful about it. See the link for details.

Cédric

Share this post


Link to post
Share on other sites
If you''re going to delete this, you have to be sure that the object was allocated with new. Something like this should work:

class foo {
public:
  static foo *create() { return new foo; }
private:
  foo() { }
};

Share this post


Link to post
Share on other sites
If you're worried about it not being created with new, then you can free() it instead of deleting it, and also call the destructor just before you free it.


void foo::Release()
{
if( m_RefCount == 1 )
{
this->~foo();
free(this);
}
else
m_RefCount --;
}


I like it better than Beer Hunter's suggestion, because if you can't trust it to be created with new, how can you trust it to be created with foo::create()?

~CGameProgrammer( );

[edited by - CGameProgrammer on August 30, 2002 2:43:27 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by CGameProgrammer
If you''re worried about it not being created with new, then you can free() it instead of deleting it, and also call the destructor just before you free it.


void foo::Release()
{
if( m_RefCount == 1 )
{
this->~foo();
free(this);
}
else
m_RefCount --;
}


I like it better than Beer Hunter''s suggestion, because if you can''t trust it to be created with new, how can you trust it to be created with foo::create()?

~CGameProgrammer( );



That''s why:
private:
foo() { }

It''s private. The only thing that can create the object is itself.

Joakim Asplund
http://megajocke.cjb.net

Share this post


Link to post
Share on other sites
quote:
Original post by CGameProgrammer
If you''re worried about it not being created with new, then you can free() it instead of deleting it, and also call the destructor just before you free it.


void foo::Release()
{
if( m_RefCount == 1 )
{
this->~foo();
free(this);
}
else
m_RefCount --;
}


I like it better than Beer Hunter''s suggestion, because if you can''t trust it to be created with new, how can you trust it to be created with foo::create()?

~CGameProgrammer( );

[edited by - CGameProgrammer on August 30, 2002 2:43:27 PM]


In Beer Hunter''s example the object can only be created by the static create method because the constructor is private (and can only be called from inside the class)

Share this post


Link to post
Share on other sites
quote:
Original post by CGameProgrammer
If you''re worried about it not being created with new, then you can free() it instead of deleting it

You must not free() something that was not allocated using malloc().

Share this post


Link to post
Share on other sites
quote:
Original post by CGameProgrammer
If you''re worried about it not being created with new, then you can free() it instead of deleting it, and also call the destructor just before you free it.


free() will blow up in exactly the same way as delete if the object is allocated on the stack. Nice try, no cigar.


"When you know the LORD you have no need for masturbation!"

Share this post


Link to post
Share on other sites
quote:
Original post by megajocke
It's private. The only thing that can create the object is itself.




Just for shits and giggles:


    
class foo
{
public:
~foo(){}
static foo* create() { foo* obj = new foo(); obj->add_ref(); return obj; }

size_t add_ref()
{
return ++m_refcount;
}
size_t release()
{
if(!--m_refcount)
{
delete this;
}
return m_refcount;
}

private:
foo(){}
size_t m_refcount;
};

void main()
{
foo* f = reinterpret_cast<foo*>(::malloc(sizeof(foo)));
// oh shit!

f->release(); // wtf

}


Yes, I know. I cheated.

Also... if you want to pass around a reference counted pointer to an object, look into boost::shared_ptr

[edited by - daerid on August 30, 2002 4:54:20 PM]

Share this post


Link to post
Share on other sites
This hasn''t come up yet.

If you want to be sure you don''t get it wrong, and also want
to be exception-safe, it''s good to have a "smart pointer"
that takes care of adding and subtracting reference counts.


  

template <typename T>
class RefPtr
{
private:
T *m_pObject;

public:
RefPtr(T *pObject) : m_pObject(pObject)
{ pObject->AddRef(); }
RefPtr(const RefPtr &Other) : m_pObject(Other.m_pObject)
{ m_pObject->AddRef(); }
~RefPtr(void)
// Release() returns true if ref count drops to 0

{ if (m_pObject->Release()) delete m_pObject; }
const RefPtr &operator=(const RefPtr &Other)
{
if (m_pObject->Release()) delete m_pObject;
m_pObject = Other.m_pObject;
m_pObject->AddRef();
return *this;
}
// end if


T *operator->(void) const
{ return m_pObject; }
T &operator*(void) const
{ return *m_pObject; }
};
// end




This class is by no means complete. I leave that as an
exercise to the reader (i.e. you) to fix the holes.

(Hint: null-pointer (I mean 0) and self-assignment...etc)



Kami no Itte ga ore ni zettai naru!

Share this post


Link to post
Share on other sites
quote:
Original post by daerid
Yes, I know. I cheated.

Not only did you cheat, you didn''t allocate a foo object. An object lifetime does not begin until the ctor has completed, and in your code no ctor for foo has been called. Basically, all you''ve achieved is to lie to the compiler, by invoking reinterpret_cast and saying "here''s some storage which is layout compatible with and contains a valid foo instance" (which, of course, it doesn''t). Any calls to foo member functions via f will invoke undefined behaviour. Quite frankly, I wouldn''t be surprised if you''ve had a few demons fly out of your nostrils whilst running that code.

Share this post


Link to post
Share on other sites
Well that''s true, free() fails if the object wasn''t created dynamically. But my point was that Beer_Hunter''s example also does not work because you can use malloc() to create the object.

But I see what you''re saying -- you meant using create() basically guarantees the object is created dynamically instead of just having a static instance of it.

~CGameProgrammer( );

Share this post


Link to post
Share on other sites
quote:
Original post by CGameProgrammer
Well that''s true, free() fails if the object wasn''t created dynamically. But my point was that Beer_Hunter''s example also does not work because you can use malloc() to create the object.
I was trying to prevent mistakes - not deliberate stupidity

Share this post


Link to post
Share on other sites
quote:
Original post by CGameProgrammer
But my point was that Beer_Hunter's example also does not work because you can use malloc() to create the object.

No you cannot. I've just told you that you haven't created the object with malloc(). Object creation is a 2-step process. First, the storage is allocated. Second the ctor is executed. You've only achieved the first, so the object has *not* been created. If you cannot gain access to the ctor of the object, then you cannot create an instance of that object. Period.

You could create another object that is layout compatible and contains the correct representation, but the effort it requires to do that should tell you that you're doing something wrong. Besides, the point of such techniques is to make it easy for the developer to get things right. It's not possible to prevent people from writing code with malicious intent, other than to fire them.

[edited by - SabreMan on August 31, 2002 5:28:32 AM]

Share this post


Link to post
Share on other sites