標籤:

如何delete數組?

這是A代碼:

void main()
{
int *p = new int[i];
delete []p;
}

這是B代碼:

void main()
{
int *p = new int[i];
delete p;
}

A與B有不同嗎,教程說有!它說B是錯的,因為這種形式的delete,只能delete掉一個元素,漏掉9個元素。

但當我打開反彙編代碼時,卻看到A和B的反彙編代碼一模一樣!!既然反彙編都一樣了,那A和B應該是等效無區別的啊!

A反彙編:

B反彙編:


真的,不要把研究自然科學的方法套用到編程上。

自然科學是通過觀察總結規律的,然後通過後續的實踐驗證規律的正確與否。如果不符合,規律就是錯的,需要重新總結。

然而編程不需要總結規律,編程的規律是人定的。如果規律和實現不符,錯的是實現,而不是規律。


「能用彙編解釋C/C++」

這種想法真是可怕。


發現這樣能正常運作也只能說明你運氣好;

正常人思路考慮,語言這麼規定有他的考慮;

從實現去想,對象數組和單個對象肯定是不一樣的——比如析構


1. 先把void main()改成 int main()

2. 對於你說的問題,比如某個動態分配的對象數組: someClass* p; p = new someClass[n]; delete p; 這種情況會導致內存泄漏。

我以前在debug的時候監控內存,發現delete p;以後分配的內存並沒有被釋放,而delete [] p; 則沒有問題。對於基本的內置類型 (比如int、double、float等),delete p;和delete [] p;都會正常釋放內存。但這並不代表你用delete p;就是對的。


擦,原來是著名的VC6。我的VS 2015 彙編代碼如下,不同處在於用delete的時候有額外的語句處理數組大小,其實也就是調用了C++14裡面的新函數:

void operator delete ( void* ptr, std::size_t sz );

其作用是:

Called if a user-defined replacement is provided except that it"s implementation-defined whether (1-4) or (5-8) is called when deleting objects of incomplete type and arrays of non-class and trivially-destructible class types (since C++17). The standard library implementations are identical to (1-4).

operator delete, operator delete[]

優化版反彙編:

// delete[]

00C91002 call operator new[] (0C91024h)

00C91007 push eax

00C91008 call operator delete[] (0C9102Dh)

00C9100D add esp,8

// delete

00C31002 call operator new[] (0C31026h)

00C31007 push 4 // 參數2 of void operator delete ( void* ptr, std::size_t sz );

00C31009 push eax // 參數1 of void operator delete ( void* ptr, std::size_t sz );

00C3100A call operator delete (0C3102Fh)

00C3100F add esp,0Ch


因為int不涉及到析構器。在vs的實現中,不帶析構器的東西在new[]的時候不額外開闢空間記錄個數,並且delete[]時直接回收內存。這塊可能做了優化,把delete和delete[]兩個運算符編譯成了一個,因為行為完全一樣。所以你new個帶析構器的類試試。


你編譯的時候把warning全開試試?有可能編譯的時候編譯器自己幫你fix這個問題了。


什麼環境……我賭五毛是vc6


我覺得你不該看彙編代碼,你應該去看new和delete的實現,看明白了,你就知道為什麼了。琢磨可以,但是別自己在那兒瞎琢磨。方法不對頭,還把自己搞的特別困惑特別累


VS幫你把活幹了 實際上不符合標準的


這個問題我以前研究過,文章在這裡:再談new/delete/malloc/free

分析過程你可以略過,當時的結論:

  1. 對於內置類型,new[]-&> 怎麼對應都不會有問題, free 只需要一個首地址,通過指針偏移可以獲取到下一個內存塊和上一個內存的地址,把這個內存塊從鏈表中刪除就 ok 了。
  2. 對於類對象數組,賦值過程中編譯器做了一些 free 層面不知道的偏移,所以一旦 new[] 和 delete[] 不對應,會發生崩潰。

這只是從技術層面去分析機制,不代表分析沒問題就可以濫用,況且這只是針對 VS2010,不同的編譯器應該會有不同的實現方式。

為了保證跨平台不會出問題,強烈建議大家還是老老實實的去找好對應關係malloc-&>free,new-&>delete,new[]-&>delete[]。遵循標準來,不要投機取巧。


看到void main我就覺得不用看下去了


B代碼依賴編譯器實現。msvc把長度放在申請到的內存的頭部,因此msvc兩種方式是相同的。


call operator delete

是什麼鬼。

你知道裡面在做什麼嗎?


寫過class試試看, POD數據沒問題。


推薦閱讀:

c/cpp 中從源代碼到可執行文件的過程,鏈接是必須的嗎?
c++中有現成的string hash函數么?
大家能談談是怎麼學習windbg的嗎?
同一個指針,作為父類類型被delete,但作為子類類型仍能訪問成員變數,為什麼?
這次dmlc發布的深度學習框架mxnet比之caffe有什麼優缺點?

TAG:彙編語言 | C |