[英]Placement new and alignment in C++
考慮以下代碼片段就地構建POD(普通舊數據)結構的實例:
#include <new>
#include <cassert>
#include <cstddef>
struct Test
{
int a;
char b;
double c;
};
int main()
{
const std::size_t minimumNumberOfBytes = sizeof( Test ) * 4;
// Get a block of memory that can accommodate a Test instance and then some!
void* const ptrToMemBlock = new char[ minimumNumberOfBytes ];
assert( ptrToMemBlock );
// Construct a Test instance in-place.
const Test* const testInstance( ::new ( ptrToMemBlock ) Test() );
// Is this assumption guaranteed to be true?
assert( testInstance == ptrToMemBlock );
}
最終斷言()所代表的假設是否保證始終是正確的? 或者可以想象編譯器可能決定構建Test實例,比如在我在placement-new調用中指定的內存塊開始之后的幾個字節?
請注意,我在這里具體詢問POD類型。 我知道,如果涉及到多個繼承和類似的東西,事情就會變得很糟糕。
這個斷言將始終成立,因為需要new
來返回具有MAXIMUM可能對齊的內存塊。 BTW - 你的第一個assert()
是沒有價值的,因為普通的new
不返回nullptr
- 它會拋出或中止,只有“nothrow new
”才能返回nullptr
。
是的,斷言將成立。 創建單個對象的任何new
表達式都必須從分配函數中請求完全sizeof(Test)
字節的存儲空間; 所以它必須將對象放在該存儲的開頭,以便有足夠的空間。
注意 :這是基於C ++ 11中新表達式的規范。 看起來C ++ 14會改變措辭,所以未來答案可能會有所不同。
是的,最后一個assert
保證保持,因為這種placement-new形式必須始終返回傳遞的指針,而不是為自己使用任何空間:
5.3.4新
[expr.new]
8 new-expression可以通過調用分配函數來獲取對象的存儲空間(3.7.4.1)。 [...]
10允許實現省略對可替換全局分配函數的調用 (18.6.1.1,18.6.1.2)。 當它這樣做時,存儲由實現提供,或者通過擴展另一個新表達式的分配來提供。 [...]
11當new-expression調用分配函數並且尚未擴展分配時 ,newexpression將請求的空間量作為std::size_t
類型的第一個參數傳遞給分配函數。 該參數不得小於正在創建的對象的大小; 僅當對象是數組時,它可能大於正在創建的對象的大小。
[...]
你的new-expression調用全局placement-new分配函數。
這是不可替換的功能,因此不能擴展或省略分配。
此外,您不是分配數組而是分配單個對象,因此根本不會發生請求填充。
18.6.1.3安置表格
[new.delete.placement]
1這些函數是保留的,C ++程序可能無法定義用於替換標准C ++庫(17.6.4)中的版本的函數。 (3.7.4)的規定不適用於
operator new
和operator delete
這些保留的安置形式。void* operator new(std::size_t size, void* ptr) noexcept;
2返回:
ptr
。
3備注:故意不執行任何其他操作。
這保證了allocation-function返回傳遞的指針不變。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.