2014-10-27 46 views
1

該標準以某種方式保證sizeof(typename aligned_storage<...>::type)是可以寫入對齊存儲的數據的實際可用大小嗎?我問這個問題的原因是我正在實現一個std :: function樣式的對象,如果該對象適合一些小的aligned_storage,就可以避免堆分配。sizeof std :: aligned_storage實際可用的存儲大小?

我看着的libC++實現的std ::函數構造函數(它做到這一點),測試他們執行,以確保傳遞類型將適合的排列存儲只是......

if (sizeof(_FF) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value) 
{ 
    __f_ = (__base*)&__buf_; 
    ::new (__f_) _FF(_VSTD::move(__f)); 
} 

其中__buf_是aligned_storage,_FF是類型擦除傳遞仿函數的包裝類,而_Fp是該仿函數類型。

我假設這不是保證,它(可能?)只是作爲aligned_storage的libC++實現的結果發生。

+0

我不確定你的想法不能保證。 sizeof(X)'是'X'的大小?如果您可以在POD數據中的任何地方寫入數據並將其視爲普通的舊數據? – Yakk 2014-10-27 17:45:06

+0

你可以寫'sizeof(__ buf_)'字節,以'&__ buf_'開始。例如,libC++中使用的實際對齊的存儲是'typename aligned_storage <3 * sizeof(void *)> :: type __buf_;'(在我的機器上)sizeof = 32,'3 * sizeof(void *)' = 24,所以對sizeof(__buf_)的檢查實際上超過了我們所要求的std :: aligned_storage的8個字節,並且顯然,放置構造函數可以在對齊的存儲之外寫入。 – pat 2014-10-27 17:58:28

+0

@pat:放置構造函數無法在對齊的存儲之外進行寫操作,而是將其向後移動。放置構造函數只使用存儲的第一部分,剩下一些「填充」。無關,對我來說似乎很奇怪,'aligned_storage'會給你額外的空間,儘管測試證實。 – 2014-10-27 18:19:20

回答

3

std::aligned_storage<len, align>::type是POD類型。這意味着它是普通的舊數據。

它是如何成爲無關緊要的。這僅僅是普通的舊數據。

現在,它有額外的保證。它也可以用於對齊存儲的大小爲len的對象,其對齊要求爲align,但這些附加要求不會將其作爲普通舊數據的保證降低。

簡單的舊數據就是它所說的:普通的舊數據。

POD類型可以複製到數組中,並從數組中複製,然後它具有「相同的狀態」。這樣的副本可以由其全尺寸([basic.types] 3.9/2)組成。對於特定行爲還有更多類似的保證。

理論上,我懷疑賦值/複製可能不會複製POD中的每個字節,但這樣做是安全的。

我想你可以有一個類型代表某種掩碼的內存,這樣memcpy會透明地忽略某些字節,並且由於類型的值僅由某些字節保存,而不是其他字節,所以被忽略的字節不是問題來自3.9的保證,但這是有問題的,而不是我能想到的任何編譯器所使用的實現。

+0

§3.9 \ 4指出,對於平凡可複製類型,所有位均在值表示中考慮,並且每個值表示表示不同的值。這意味着副本必須保留所有位。 – 2014-10-27 18:29:41

+0

@MooingDuck我可以閱讀3.9 \ 4,但我沒有看到這種解釋。「對於普通可複製類型,值表示是對象表示中的一組位,它確定了一個值」 - 「一組位,用於確定一個值」。如何保證所有位都被使用? (在這裏使用N3797)。基本上,這是POD:'struct foo {char a; int b; }',但填充可能在'a'和'b'之間,所以這些字節不會影響'foo'的*值*。使memcpy對這些字節不起作用的魔術內存似乎是合法的? – Yakk 2014-10-27 18:37:13

+0

「對於可複製類型,值表示是對象表示中的一組位,用於確定一個值,該值是實現定義的一組值的一個離散元素。」對象表示的每一位(sizeof(T)中的所有位)參與該值。如果您將一個實例複製到另一個位置,則它必須具有相同的值。由於所有位參與該值,所以它必須具有所有相同的位。 – 2014-10-27 18:39:05