2013-11-21 73 views
6

因此,在代碼審查期間,我的同事使用double* d = new double[foo];,然後調用delete d。我告訴他們,他們應該將其更改爲delete [] d。他們表示,編譯器不需要基本的數據類型。我不同意。是刪除和刪除基本數據類型的[]等效

所以我想我會證明我的觀點有一個實驗:

#define NUM_VALUES 10000 
int main(int argc,char** argv) 
{ 
    int i = 0; 
    while (true) 
    { 
    std::cout << i << "|"; 
    double* d = new double[NUM_VALUES]; 
    std::cout << ((void*)d) << std::endl; 
    for (int j = 0; j < NUM_VALUES; j++) 
     d[j] = j; 

    delete d; 
    i++; 
    } 

    return 0; 
} 

不僅內存使用量沒有增長,但d被分配到每一個時間同一個地方! (Visual Studio 2010)。這是一個Visual Studio編譯器的怪癖嗎?或者這是標準的一部分?

+6

你的同事是錯的,他應該感覺不好。 – 2013-11-21 16:45:31

+0

[刪除vs刪除\ [\]](http://stackoverflow.com/questions/4255598/delete-vs-delete) – andre

+0

可能的重複[是刪除\ [\]等於刪除?](http ://堆棧溢出。com/questions/1553382/is-delete-equal-to-delete) – Angew

回答

10

如果使用new你需要如果您使用new [],你必須使用delete []

他們意味着不同的事情用delete

double* d = new double();意味着分配和構造一個雙重類型。 delete d;表示未分配並銷燬單個雙重類型。 double* d = new double[NUM_VALUES];表示分配NUM_VALUES雙打,delete [] d表示未分配NUM_VALUES中的每一個分配的雙打。

+0

我同意你的說法,安德烈並沒有質疑。但是,這並不能解釋爲什麼我的實驗不會爆炸。這是因爲行爲沒有定義? – IdeaHat

+3

@MadScienceDreams正是如此。刪除'new []'ed對象會導致未定義的行爲。 – 2013-11-21 16:45:55

+0

啊所以這是一個編譯器怪癖,不應該依賴。謝謝。 – IdeaHat

5

我告訴他們,他們應該將其更改爲delete [] d

你是對的。使用delete的錯誤形式會導致未定義的行爲。

這是一個Visual Studio編譯器的怪癖嗎?或者這是標準的一部分?

這是很有可能的實施將獲得來自同一個地方的記憶都「單個對象」和「陣」的分配,在這種情況下使用的delete錯誤的形式瑣碎的類型會出現工作。釋放內存然後分配相同數量的內存很可能會重用相同的內存。不過,這些標準都不能保證。

1

你是完全正確的,在你的分歧。

正如已經多次指出的那樣,new/deletenew[]/delete[]是兩個獨立的,完全獨立的動態內存管理方式。不能混用它們(如使用delete分配給new[]的內存),無論它們與何種類型一起使用。

這兩種機制很容易在物理上有所不同,即它們可以使用完全不同的內存佈局,完全不同的內存池,甚至可以使用完全不同類型的系統級內存。

所有這些甚至沒有提到在語言層面上這些機制所使用的原始內存分配函數(operator new()函數和其他函數)是可獨立替換的,這意味着即使這些運算符的無意混合似乎「有效」對於實現中的基本類型,可以通過原始內存分配替換很容易地破壞它。

1

首先對這個問題的接受答案delete vs delete[]引用標準,說行爲是未定義的。這應該滿足你的同事。這裏有更多的討論:Is delete[] equal to delete?

如果他不服氣,你可以提醒他說,全球new/delete,以及,全球new[]/delete[]可能在那些對被覆蓋,所以即使new[]/delete對(基本型)的VS2010實現做不崩潰,絕對不能保證另一個實現不會失敗。

例如,我們在調試模式下覆蓋了全局new[]/delete[],以隱藏「數組結束標記」以驗證使用情況。我們當然期望delete[]new[]創建的雙打數組上被調用,以使其工作。

但是,因爲我在舊的C++呃,我知道你的同事混淆的來源。考慮最簡單的實現new/deletenew[]/delete[]使用C的malloc/free作爲後端,並直接調用構造函數/析構函數。很容易看出,對於簡單的實現,由於原始的C++實現,deletedelete[]對於沒有析構函數的類型是等效的。圍繞這一點建立了某種民間文學藝術,這可能是你的同事聲明的來源,但它並沒有在現實中成立,事實上從來沒有。

+0

好找。這個答案解釋得非常好。 – andre

1

作爲參考,它似乎工作的原因是,在您的實現:

  • 他們都得到他們的記憶來自同一來源
  • 作爲一種優化,爲double(可能一些其它類型) new[]不使用任何存儲陣列請求大小的內存。對於具有析構函數delete[]的類型,需要知道要銷燬多少個對象,以便大小必須存儲在某處。

事實上,這是一個特別的實施的行爲是不依賴於這種行爲的好理由。

主要原因代碼是容易出問題的一些實施,地方,如果是爲new[]陣列加上其規模空間分配空間,並返回一個指針數組。然後delete[]會在釋放分配之前減去用於大小的空間,而delete則不會。您的同事選擇了從不遇到與new double[]這樣做的實現。

這一必要的數量可以總是由從由非標準功能,如malloc_size()返回的值的C++實現推斷,由於返回用於滿足分配,而不是要求的尺寸的塊的尺寸。所以通常人們應該期望new[]delete[]使用一些技巧或其他,並且它純粹是一種執行質量問題,它們避免使用它們的類型。

即使該實現足夠智能以避免需要額外空間與數組double,它可能有一個故意檢測錯誤的調試模式。