2014-01-24 82 views
0

我有一個類A和我創建了一個指針:如何分配內存以及如何釋放內存?

A * const q = reinterpret_cast<A * const>(new char[2 * sizeof(A)]); 

,我有2個OBJETS:

new (q)A; 
new (q + 1) A; 

如果我刪除指針這樣的:

  • delete q;它被調用有一次的破壞者A
  • delete[] reinterpret_cast<char *>(q);還有沒有~A()
  • delete q; delete (q+1);呼叫沒有馬瑟秩序崩潰
  • delete [] q也崩潰

正確的方法,我覺得是這樣的:

q->~A(); 
q[1].~A(); 
delete[] reinterpret_cast<char *>(q); 

誰能告訴我,爲什麼和內存分配/釋放是怎麼回事?

回答

2

new A最常見的實現是分配足夠的內存用於存儲1 A對象並返回分配地址(以及之後的對象的調用構造函數)。

new A[x]另一方面必須跟蹤x數量A分配的對象。 x通常存儲在第一個分配字段中,並且new[]返回該字段之後的地址(以便它指向數組的實際起始位置)。

在你的擰緊的情況下,第一個字段根本沒有分配。 delete[]不能確定A的數量(它會嘗試,但是在給定指針的負偏移處將會有堆塊頭)。所以你必須顯式調用每個對象的析構函數,然後用deletedelete[]爲任何內置類型指針釋放內存,否則它將嘗試調用析構函數。

編輯:(忘了補充)的內置在通常的實現類型沒有數量字段「

堆分配陣列的原因,他們並不需要析構函數被調用。這就是爲什麼你的new char[]delete [] reinterpret_cast<char *>(q)不同於new[]delete[]A

3

當然,您不能在實例上調用delete,該實例假定它將執行new的計數器並釋放內存。它無法知道您是否已經使用placement-new爲對象分配後備存儲。我認爲最後的片段也是正確的:運行析構函數並手動釋放內存,因爲只有你知道它來自哪裏。

+0

所以它可能來自其他地方,這就是爲什麼'reinterpret_cast (new char [2 * sizeof(A)]''被使用? –

2

分配器通常存儲節點旁邊(鏈表指針指向下一個節點,大小等)的分配信息。

正因爲如此,你只能爲你叫分配相同的對象釋放器(delete)。否則,你在UB境內,釋放器將解釋作爲存儲的額外信息的錯誤的部分,你的代碼可能會崩潰..

的最後一個例子是正確的。

但是,我認爲你可能有對齊問題,因爲內存分配給 char[]而不是 A

+0

這意味着整個'char [2 * sizeof(A)]'是爲單個'A'對象分配的內存嗎? –

+0

呵呵?沒有。我真的不明白你的問題。 –

+0

@KarolyHorvath由'new char [X]'(或'unsigned char')返回的內存適合任何大小不超過X的對象。 – jrok

1

是,最後一個例子是正確的。

經驗法則是,你只能從new(當然只有一次)得到delete。這同樣適用於陣列版本。

new[]得到了什麼是char*,我想很明顯你會如何將其刪除。

另外,如果您使用投放新構造一個對象,你負責手動調用析構函數(如果它需要)。

+0

棘手的部分是*放置刪除*'。 – Jarod42

+0

@ Jarod42因爲它不存在?你能否詳細說明一下? – jrok

+0

我的意思是我們對每個'new'使用'delete',但是用於放置'new'的(不存在)'placement'delete''是'〜T'語法,看起來可能不自然。 – Jarod42