2010-02-22 66 views
5

我目前正在学习COM和下面的代码混淆了我。成员方法如何删除对象?

STDMETHODIMP _(ULONG) ComCar::Release() 
{ 
    if(--m_refCount==0) 
    delete this; // how could this "suicide" deletion be possible? 
    return m_refCount; 
} 

我想知道如何删除其成员方法内的对象实例?所以,我做了以下实验:

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 
} 

和执行并未能在a.Suicide()。调试报告中有一些“Debug Assertion Failed”。有人可以点亮我吗?因为我完全是COM上的新手。

一个相关的线程是在这里:Question about COM Release() method

回答

10

你的主要的身体更改为:

A* a = new A(); 
a->name='a'; 
a->Sucide(); 

只能删除什么用new建,当然 - 这使得如果删除是没有区别的在成员职能或其他地方。

7

在你的例子中,Suicide()失败,因为它调用了一个未被动态分配的对象的delete,无论调用函数是否为成员都是无效的。

成员函数deletethis - 如果他们知道this指针已被动态分配(通过new)。在return声明

STDMETHODIMP _(ULONG) ComCar::Release() 
{ 
    if(--m_refCount==0) 
    delete this; // how could this "sucide" deletion be possible? 
    return m_refCount; 
} 

结果不确定的行为:但是,他们不能在该点之后访问成员,因此,严格来说,你给的例子。

+3

而简单的修复方法当然是返回0。 – GManNickG

+0

谢谢,迈克尔,既然你提到“动态分配”,我猜测是否有一些相反的“静态分配”?它是什么和有什么区别?也许很难用一句话来解释它。你能否给我一些参考资料供进一步研究?非常感谢。 :D – smwikipedia

+1

@GMan:只是想澄清你的意思:'if(--m_refCount == 0){delete this;返回0; }返回m_refCount;'。你不能把return语句改成'return 0;'。 – Dan

1

使用new通过调用delete来分配要销毁的新类对象。

2

您不能删除未动态分配的对象。 COM对象是动态分配的。

这工作:

#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 
} 
3

delete this是有效的,只有当对象是使用new操作符分配。对于COM引用计数,这并不罕见。

但是,还有一个警告:在delete this未定义之后访问成员变量,因为该对象的内存已经返回到空闲存储区。您发布的第一个代码示例执行此操作。要修复它,请使用局部变量:

STDMETHODIMP_(ULONG) ComCar::Release() 
{ 
    ULONG refCount = --m_refCount; 
    if(refCount==0) 
    delete this; 
    return refCount; 
} 
+1

我个人发现它有点混乱,局部变量。如果你知道它在if语句中是零,只返回0. – GManNickG

+2

@GMan,但是你需要两个return语句,一个在'if'和一个在外 - bk1e的方法可以节省重复! –

+0

而不是复制return语句,我们复制值\ *耸肩* *也许这是一个更清洁。 – GManNickG

1

这是一个简单的原因。 新增和删除必须匹配。

所以,如果你在一个DLL中创建一个对象,并将它处理到另一个部分(exe,dll),C运行时可能会有所不同。在这种情况下,您不能调用delete,因为运行时没有关于要删除的指针的知识。它可能会崩溃。

因为这是一个很好的设计来整合自杀方法。 Com中有一对方法。

AddRef 
Release 

这意味着指针有一个计数器来记住一个对象有多少个拥有者。 只有最后一个所有者调用删除时,该对象才会真正被删除。

但我认为您发布的实施中存在错误。

return m_refCount; 

当对象被删除时应该是不可能的。至少行为是未定义的。我认为你需要将m_refCount存储在局部变量中以在删除情况下返回它。

STDMETHODIMP _(ULONG) ComCar::Release() 
{ 
    if(--m_refCount==0) { 
    delete this; // how could this "sucide" deletion be possible? 
    return 0; 
    } 
    return m_refCount; 
}