簡體   English   中英

在C ++中,是與指針關聯的動態數組的長度信息還是第一個元素的地址?

[英]In C++, is the length information of a dynamic array associated with the pointer or the address of the first element?

例如:

int *a, *b;
a = new int[10];
b = new int(12);
b = a; // I know there's memory leak, but let's ignore it first
delete [] b; // line L

會發生什么? 整個陣列會被成功刪除嗎?

如果用這個代替行L:b = a + 1; 刪除[] b;

或者通過這個:a ++; 刪除[] a;

最后,如果動態數組的長度與起始地址相關聯,或者換句話說,與數組本身相關聯,我們是否有辦法獲得它的長度而不使用另一個變量來存儲長度?

非常感謝!

存儲塊大小和數組長度信息與對象的地址相關聯,該地址是數組的第一項的地址。

即你的delete[]在給定的代碼中是安全的

int *a, *b;
a = new int[10];
b = new int(12);
b = a; // I know there's memory leak, but let's ignore it first
delete [] b; // line L

然而,有一個1次 訪問相關信息中沒有可移植的方法。 這是一個實現細節。 如果需要這樣的信息,請使用std::vector


要了解無法訪問信息的原因,請首先注意,釋放所需的內存塊大小可能大於數組長度乘以數組項的大小。 所以我們在這里處理兩個不同的值。 對於POD項類型的數組,其中不需要項析構函數調用,不需要顯式存儲的數組長度值。

即使對於需要析構函數調用的數組,也不需要顯式存儲與數組關聯的數組長度值。 例如,在模式的代碼中p = new int[n]; whatever(); delete[] p; p = new int[n]; whatever(); delete[] p; ,編譯器原則上可以選擇將數組長度放在一些不相關的地方,在那里可以通過為delete表達式生成的代碼輕松訪問它。 例如,它可以放在處理器寄存器中。

根據編譯器的智能程度,不一定需要顯式存儲的內存塊大小。 例如,編譯器可以注意到在某個函數f ,分配了三個數組abc ,它們的大小在第一次分配時已知,並且所有三個在結束時都被解除分配。 因此編譯器可以用一個分配替換三個分配,並且用一個分配替換三個分配(這個優化是由2 C ++14§5.3.4/ 10明確允許的)。


1除了在C ++ 14及更高版本中,在釋放函數中,這有點晚。
2 C ++14§5.3.4/ 10:“允許實現省略對可替換全局分配函數的調用(18.6.1.1,18.6.1.2)。 當它這樣做時,存儲由實現提供,或者通過擴展另一個新表達式的分配來提供。 該實現可以擴展新表達式 e1的分配,以便為新表達式 e2提供存儲,如果......“

int *a, *b;
a = new int[10];
b = new int(12);
b = a; // I know there's memory leak, but let's ignore it first
delete [] b; // line L

整個陣列會被成功刪除嗎?

是的,因為指針a被設置為指向10個整數的數組,所以將成功釋放內存

a = new int[10];

然后將相同的存儲器位置地址存儲到b

b = a;

因此delete[]行正確釋放數組塊

delete [] b;

如您所述,代碼還泄漏了最初由b分配和指向的整數變量12。

作為旁注調用delete[]來釋放與數組無關的內存(特別是靜態類型不匹配 - 請參閱[expr.delete] / p3 )會觸發未定義的行為。


現在對於一些內部,在分配內存時存儲的大小信息在哪里。

編譯器在內存分配請求方面具有一定的自由度(參見§5.3.4/ 10)(例如,它們可以“分組”內存分配請求)。

當你在沒有提供分配器的情況下調用new ,無論它是否會調用malloc ,它都是實現定義的

[new.delete.single]

執行循環:在循環內,函數首先嘗試分配請求的存儲。 是否未指定嘗試是否涉及對標准C庫函數malloc的調用。

假設它調用malloc() (在最近的Windows系統上它調用UCRT ),嘗試分配空間意味着使用分頁虛擬內存進行簿記,這就是malloc通常所做的事情。

您的大小信息與其他有關如何分配您請求的內存的數據一起傳遞。

glibc這樣的C庫負責對齊,內存保護和新頁面的分配(如果需要),因此這可能會通過系統調用結束在內核中。

沒有“標准”方法可以從地址中獲取該信息,因為它是一個實現細節。 正如許多人所建議的,如果你需要這樣的信息,你可以

  • 在某處存放大小
  • sizeof()與數組類型一起使用
  • 更好的C ++:使用std::vector<>

該信息還與內存分配相關聯,這兩種情況都是相關的(即用L代替

b = a + 1; delete [] b;

要么

a++; delete [] a;

因為這些地址與有效分配無關,所以會以淚水結束。

c ++標准只是說在使用new分配的指針上使用delete[] ,並且在使用new[]分配的指針上使用delete是未定義的行為。

這樣做可能有效,也可能不行,具體取決於實現方式。 它可能會讓你的房子着火。

例如,假設這些函數基於使用malloc()和free()的底層緩沖區。

在大多數實現中, newdelete將使用具有項目大小和地址的緩沖區(此處為int

new[]delete[]更復雜。 他們必須在緩沖區中不僅存儲size的物品,也值size 實現可以在實際項目之前存儲size 這意味着底層緩沖區的指針與指向第一個項目的指針不同,后者是new[]返回的值

混合數組和非數組版本然后會在無效指針上調用free(),即malloc從未返回的指針。 這將崩潰或觸發異常

當然,所有這些都是實現定義的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM