簡體   English   中英

在C ++中放置新的和對齊

[英]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 newoperator delete這些保留的安置形式。

 void* operator new(std::size_t size, void* ptr) noexcept; 

2返回: ptr
3備注:故意不執行任何其他操作。

這保證了allocation-function返回傳遞的指針不變。

暫無
暫無

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

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