簡體   English   中英

重新分配用 new 分配的內存是否安全?

[英]Is it safe to realloc memory allocated with new?

這里所寫的內容來看, new自由存儲中分配,而malloc使用,這兩個術語通常意味着相同的事情。

這里寫的內容來看, realloc可能會將內存塊移動到新位置。 如果 free store 和 heap 是兩個不同的內存空間,那么這是否意味着任何問題?

具體來說,我想知道使用是否安全

int* data = new int[3];
// ...
int* mydata = (int*)realloc(data,6*sizeof(int));

如果沒有,是否有任何其他方式來realloc內存分配的new安全? 我可以分配新區域並memcpy內容,但據我所知,如果可能, realloc可能會使用相同的區域。

您只能realloc是對已經通過分配malloc (或家庭,如calloc )。

這是因為跟蹤空閑和已用內存區域的底層數據結構可能大不相同。

可能但絕不保證 C++ new和 C malloc使用相同的底層分配器,在這種情況下realloc可以對兩者都有效。 但正式地說,那是在UB-land。 在實踐中,這只是不必要的風險。


C++ 不提供對應於realloc功能。

最接近的是像std::vector這樣的容器(的內部緩沖區)的自動重新分配。

C++ 容器的設計方式不包括realloc使用。


而不是呈現的代碼

int* data = new int[3];
//...
int* mydata = (int*)realloc(data,6*sizeof(int));

… 做這個:

vector<int> data( 3 );
//...
data.resize( 6 );

但是,如果您絕對需要realloc的一般效率,並且如果您必須接受new用於原始分配,那么您唯一的效率方法就是使用特定於編譯器的方法,了解realloc對於此編譯器是安全的。

否則,如果您絕對需要realloc的一般效率但又不被迫接受new ,那么您可以使用mallocrealloc 使用智能指針可以讓您獲得與使用 C++ 容器相同的安全性。

C++ 對realloc添加的唯一可能相關的限制是 C++ 的malloc / calloc / realloc不能在::operator new方面實現,它的free不能在::operator delete方面實現(根據 C++14 [ c.malloc]p3-4)。

這意味着您正在尋找的保證在 C++ 中不存在。 但是,這也意味着您可以根據malloc實現::operator new 如果你這樣做,那么理論上, ::operator new的結果可以傳遞給realloc

在實踐中,您應該擔心new的結果與::operator new的結果不匹配的可能性。 例如,C++ 編譯器可以組合多個new表達式以使用單個::operator new調用。 這是編譯器在標准不允許的情況下已經做的事情,IIRC,現在標准允許它(根據 C++14 [expr.new]p10)。 這意味着即使你走這條路,你仍然不能保證將你的new指針傳遞給realloc做任何有意義的事情,即使它不再是未定義的行為。

一般來說,不要這樣做。 如果您使用具有非平凡初始化的用戶定義類型,則在重新分配復制釋放的情況下,您的對象析構函數將不會realloc調用 復制時也不會調用復制構造函數 由於對象生命周期的不正確使用,這可能會導致未定義的行為(參見C++ 標准 §3.8 對象生命周期,[basic.life] )。

1 對象的生命周期是對象的運行時屬性。 如果一個對象屬於類或聚合類型,並且它或它的一個成員是由一個非平凡默認構造函數初始化的構造函數,則稱該對象具有非平凡初始化。 [ 注意:通過簡單的復制/移動構造函數初始化是非平凡的初始化。 ——尾注]

類型 T 的對象的生命周期在以下情況下開始:

— 獲得了類型 T 具有正確對齊和大小的存儲,並且

— 如果對象具有非平凡的初始化,則其初始化已完成。

類型 T 的對象的生命周期在以下情況下結束:

— 如果 T 是具有非平凡析構函數的類類型 (12.4),則析構函數調用開始,或

— 對象占用的存儲空間被重用或釋放。

后來(強調我的):

3 本國際標准中賦予對象的屬性適用於給定對象在其生命周期內

所以,你真的不想在一個對象的生命周期之外使用

它不安全,也不優雅。

可能可以覆蓋 new/delete 以支持重新分配,但您也可以考慮使用容器。

一般來說,沒有。

有很多事情必須堅持以確保安全:

  1. 按位復制類型並放棄源必須是安全的。
  2. 析構函數必須是微不足道的,或者您必須就地銷毀要釋放的元素。
  3. 要么構造函數是微不足道的,要么必須就地構造新元素。

平凡類型滿足上述要求。

此外:

  1. new[] - 函數必須將請求不作任何更改地傳遞給malloc ,也不做任何簿記。 您可以通過替換全局 new[] 和 delete[] 或相應類中的替換來強制執行此操作。
  2. 編譯器不得要求更多內存以保存分配的元素數量或其他任何內容。
    沒有辦法強制這樣做,但如果類型具有作為實現質量問題的微不足道的析構函數,則編譯器不應保存此類信息。

是的 - 如果new實際上首先調用malloc (例如,這就是 VC++ new工作方式)。

沒有別的。 請注意,一旦您決定重新分配內存(因為new稱為malloc ),您的代碼是特定於編譯器的,並且不再在編譯器之間移植。

(我知道這個答案可能會讓許多開發人員感到不安,但我的答案取決於實際情況,而不僅僅是慣用語)。

那是不安全的。 首先,您傳遞給realloc的指針必須是從mallocrealloc獲得的: http : //en.cppreference.com/w/cpp/memory/c/realloc

其次, new int [3]的結果不必與分配函數的結果相同——可以分配額外的空間來存儲元素的數量。

(對於比int更復雜的類型, realloc不安全,因為它不調用復制或移動構造函數。)

您可能能夠(並非在所有情況下),但您不應該這樣做。 如果您需要調整數據表的大小,則應改用std::vector

其他SO 問題中列出了有關如何使用它的詳細信息。

這些函數主要用在 C 中。

memset 將內存塊中的字節設置為特定值。

malloc 分配一塊內存。

calloc,與 malloc 相同。 唯一的區別是它將字節初始化為零。

在 C++ 中,分配內存的首選方法是使用 new。

C: int intArray = (int*) malloc(10 *sizeof(int)); C++:int intArray = new int[10];

C: int intArray = (int*) calloc(10 *sizeof(int)); C++: int intArray = new int10;

暫無
暫無

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

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