2010-02-22 50 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; 
}