可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am currently studying COM and the following code confused me.
STDMETHODIMP _(ULONG) ComCar::Release()
{
if(--m_refCount==0)
delete this; // how could this "suicide" deletion be possible?
return m_refCount;
}
I am wondering how could it be possible to delete an object instance within its member method? So I made the following experiment:
class A
{
public:
void Suicide(void);
void Echo(void);
char name;
};
void A::Echo(void)
{
::printf("echo = %c\n",name);
}
void A::Suicide(void)
{
delete this;
}
int main(void)
{
A a;
a.name='a';
a.Suicide(); //failed
}
And the execution does failed at a.Suicide(). The debug report some "Debug Assertion Failed". Could someone shed some light on me? Cause I am totally a newbie on COM.
A related thread is here: Question about COM Release() method
回答1:
Change your main's body to:
A* a = new A();
a->name='a';
a->Sucide();
You can only delete what was built by new
, of course -- it makes no difference if that delete is in a member function or elsewhere.
回答2:
In your example, Suicide()
fails because it's calling delete on an object that hasn't been dynamically allocated, which is invalid whether or not the calling function is a member.
Member functions can delete
this
- if they know the this
pointer has been dynamically allocated (via new
). However, they can't access members after that point, so strictly speaking the example you gave:
STDMETHODIMP _(ULONG) ComCar::Release()
{
if(--m_refCount==0)
delete this; // how could this "sucide" deletion be possible?
return m_refCount;
}
results in undefined behavior at the return
statement.
回答3:
delete this
is valid only when the object was allocated using the new operator. For COM reference counting, this is not unusual.
However, there is another caveat: accessing member variables after delete this
is undefined, because the memory for the object has already been returned to the free store. The first code sample you posted does this. To fix it, use a local variable:
STDMETHODIMP_(ULONG) ComCar::Release()
{
ULONG refCount = --m_refCount;
if(refCount==0)
delete this;
return refCount;
}
回答4:
You cannot delete an object that was not dynamically allocated.
COM objects are dynamically allocated.
This works:
#include <stdio.h>
class A
{
public:
void Sucide(void);
void Echo(void);
char name;
};
void A::Echo(void)
{
::printf("echo = %c\n",name);
}
void A::Sucide(void)
{
delete this;
}
void main(void)
{
A *a = new A;
a->name='a';
a->Sucide(); // works
}
回答5:
Use new
to allocate new object of class which your going to destroy by calling delete
.
回答6:
There is a simple reason for this.
new and delete must match.
So if you create an object in an dll and handle it to another part (exe, dll) C runtime might be different. In this case you can not call delete because the runtime has no knowlegde about the pointer you want to delete. It might crash.
Because of this its a good design to integrate the suicide method. In Com its a pair of methods.
AddRef
Release
which means that the pointer has a counter to remember how many owner an object has.
Only if the last owner calls delete the object is really deleted.
But I think there is an error in the implementation you posted.
return m_refCount;
should not be possible when the object is deleted. At least the behavior is undefined. I think you need to store m_refCount on an local variable to return it in delete case.
STDMETHODIMP _(ULONG) ComCar::Release()
{
if(--m_refCount==0) {
delete this; // how could this "sucide" deletion be possible?
return 0;
}
return m_refCount;
}