日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

對象析構談—— delete this 的使用及注意事項

系統 1926 0

對象析構談—— delete this 的使用及注意事項 (轉自: http://blog.csdn.net/weiqubo/article/details/4746969

In order to understand "delete this" :

First Step - dive into "delete p "

delete p 執行了哪些步驟?
delete p 是一個兩步的過程:調用析構函數(釋放類里邊涉及new的內存),然后釋放內存(類本身占的內存)。

delete p產生的代碼看上去是這樣的(假設是Object*類型的):

delete原語可以看作如下這樣一個過程:
p->~Object();
p->operator delete(p);

p->~Object() 語句調用p指向的Object對象的析構函數。
p->operator delete(p) 語句調用對象p的內存釋放原語 void operator delete(void* p)。如果沒有實現該方法,將調用系統的內存釋放原語::operator delete(ptr)做釋放該對象內存的操作。 當然細節上并不這么簡單,我們最后的實驗部分會詳細討論

Second Step - "delete this"

成員函數調用delete this合法嗎?
只要你小心,一個對象請求自殺 (delete this) 是可以的。

以下是我對“小心”的定義:

你必須100%的確定,this對象是用 new分配的(不是用new[],也不是用定位放置 new,也不是一個棧上的局部對象,也不是全局的,也不是另一個對象的成員,而是明白的普通的new)。

你必須100%的確定,該成員函數是this對象最后調用的的成員函數。

你必須100%的確定,剩下的成員函數(delete this之后的)不接觸到this對象任何一塊(包括調用任何其他成員函數或訪問任何數據成員)。

你必須100%的確定,在delete this之后不再去訪問this指針。換句話說,你不能去檢查它,將它和其他指針比較,和NULL比較,打印它,轉換它,對它做任何事。

自然,對于這種情況還要習慣性地告誡:當你的指針是一個指向基類類型的指針,而沒有虛析構函數時(也不可以delete this)。

注意:因為是在類成員函數里面delete this的,所以在此語句以后,不能訪問任何的成員變量及 函數(調用虛函數必須對象實例存在以檢查類型),否則一定非法。

上面所說的在執行時不一定會報錯,但盡量不要這么做。

Some test examples:

析構函數本身是不會釋放內存的,
除非在析構函數里面顯示的使用delete操作符.
在對類指針使用delete時,實際發生了兩個步驟。
A:先是調用該類的析構函數,以做數據成員的釋放工作,以及一些finish code,這一切由程序員自己定義。
B:然后再調用operator delete(void*)釋放該對象實例的內存數據。這是一個對象在消亡之前的所做的最后動作。 一般不要 override這個函數,如果要,務必記住最后調用系統的::operator delete真正釋放該對象所占用的內存
一般來說,內存釋放釋放的只能是數據段的內容(包括堆和棧,但釋放棧上的內存由系統進行),而代碼段的內存,除一些病毒攻擊等非正常強行改寫手段外,在內存中是永遠不會釋放/改變的,直到程序結束,因此在內存釋放后也是可以訪問的。 所以,一般所謂的釋放內存 delete操作,是在數據段進行的釋放
可以試試下面的代碼
Example 1: 兩步操作
class x {
public :
??????? x(){}
??????? ~x() {
??????????????? printf("%s/n","~x()");
??????? }
};
void main() {
??????? x* p=new x;
??????? ::operator delete(p); //調用delete內存釋放原語,不會調用~x(),如果確實調用了系統::operator delete,就沒有內存泄露(也可能由用戶函數覆蓋)
??????? delete p; //~x()依然會執行,operator delete中將會報錯(最后將討論)
}
Example 2: override 重寫的operator delete
class x {
public :
??????? x(){
??????? }
??????? ~x() {
??????????????? printf("~x()/n");
??????????????? //delete p; //這里若進行此操作則會陷入嵌套
??????? }
??????? void operator delete(void * ptr) {
??????????????? printf("x::delete()/n");
??????? }
};
void main() {
??????? x* p=new x;
??????? delete p; //依次調用p的~x()和operator delete
??????? delete p; //不會報錯,因為"operator delete" override了系統函數,沒有進行::operator delete(this)操作。
??????? delete p; //同理依然不會報錯
}
Example 3: 默認的operator delete
class x {
public :
??????? x(){
??????????????? //delete p; //構造時delete不會報錯,只要確保以后不會用到該實例(包括delete p)。
??????? }
??????? ~x() {
??????????????? printf("~x()/n");
??????? }
};

void main() {
??????? x* p=new x;
??????? delete p; //依次調用p的~x()和operator delete(其中調用了系統的::operator delete)
??????? //delete p; //報錯,這里沒有override,對象調用的是系統的::operator delete
}

進一步分析:
讓我們看一下系統::operator delete的內部實現(in dbgdel.cpp):
void operator delete(
??????? void *pUserData
??????? )
{
??????? _CrtMemBlockHeader * pHead;

??????? RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));

??????? if (pUserData == NULL)
??????????? return;

??????? _mlock(_HEAP_LOCK); /* block other threads */
??????? __TRY

/* get a pointer to memory block header */
??????????? pHead = pHdr(pUserData);

/* verify block type */
??????????? _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)); //檢查該段內存是否被程序占用。一般出現的如果內存已經釋放了,又執行內存釋放操作,這里就會報錯

??????????? _free_dbg( pUserData, pHead->nBlockUse );

??????? __FINALLY
??????????? _munlock(_HEAP_LOCK); /* release other threads */
??????? __END_TRY_FINALLY

??????? return;
}
如果在里面設置斷點,無論是直接調用::operator delete還是類似delete p調用對象的operator delete,如果沒有人為override,都會進入這個函數,進行釋放內存的操作。因此一個C++的類其實可以看做是有一個類似java的Object在內部進行操控:

class object {
public :
??????? object() { }
??????? ~object() { }
??????? void operator delete(void *ptr) {
??????????????? ::operator delete(ptr);
??????? }
};

delete原語看起來會是如下的樣子:
p->~object();
object::operator delete(p);

因為代碼段的內存是不會被釋放的,因此無論對象p的內存有沒有釋放,這兩個語句都會執行,不會因為p沒有指向任何存在的對象而報錯,只是在最后執行到::operator delete的時候,才會在執行_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse))的時候報錯。

Example 4: 代碼段不會被釋放
class x {
public :
??? x(){printf("x()/n"); }
??? ~x() {
??????? printf("~x()/n");
??????? operator delete(this);
//以下并不會報錯
??????? int n=~get(34);//返回-6(~5)
??????? x(); //會連帶調用x()->~x()->operator delete
??? }
??? void operator delete(void *p) { // 這其實是一個靜態函數 ,成員函數調用不能放在里面
??????? ::operator delete(p);
??????? printf("x::delete()/n");
??? }
??? int get(int ) { //注意這個申明是合法的
??????? printf("x::get()/n");
??????? return 5;
??? }
};

int main()
{
??? x* p=new x;
??? x::x(); //合法的,會連帶調用x()->~x()->operator delete,但會因為具體對象不存在而報錯
??? //p->x(); //調用非法,編譯不通過
??? delete p;
??? int num = p->get(1); //不會報錯,返回5
}

Example 5: 釋放內存只釋放數據段
class x {
public :
??? int n;
??? x() {
??????? printf("x()/n");
??????? n=5;
??? }
??? ~x() {
??????? printf("~x()/n");
??? }
??? void operator delete(void *p) { // 這其實是一個靜態函數 ,成員函數調用不能放在里面
??????? ::operator delete(p);
??????? printf("x::delete()/n");
??? }
??? int get(int ) {
??????? printf("x::get()/n");
??????? return n;
??? }
??? void test() {
??????? delete this;
//以下并不會報錯
??????? int n=this->get(34); //會得到一個非法值,不是5
??? }
};

int main()
{
??? x* p=new x;
??? p->test();
??? delete p;
??? int num = p->get(1); //會得到一個非法值,不是5
}

對象析構談—— delete this 的使用及注意事項


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 临猗县| 和平区| 济源市| 日照市| 保亭| 柞水县| 锦屏县| 甘德县| 包头市| 长阳| 千阳县| 平乐县| 会同县| 丰县| 石嘴山市| 湛江市| 凌海市| 神木县| 车致| 龙州县| 壤塘县| 忻州市| 宁都县| 博白县| 青神县| 普兰店市| 无为县| 义马市| 绥阳县| 繁峙县| 莎车县| 乌海市| 玛沁县| 祥云县| 黄石市| 方山县| 灵川县| 新民市| 壶关县| 大姚县| 上林县|