2012-10-25 43 views
2

考慮下面的類:將sizeof和placement放置在一起可以安全嗎?

template <class T> 
class defer { 
public: 
    template <class ...Args> 
    void construct(Args&&...); 
    T& obj(); 
    ~defer(); 
private: 
    std::uint8_t memory[sizeof(T)]; 
    T * ptr(); 
}; 

template <class T> 
template <class ...Args> 
void defer<T>::construct(Args&& ...args) { 
    new(static_cast<void*>(&memory[0])) T(std::forward<Args>(args)...); 
} 

template <class T> 
T& defer<T>::obj() { 
    return *(ptr()); 
} 

template <class T> 
defer<T>::~defer() { 
    ptr()->~T(); 
} 

template <class T> 
T * defer<T>::ptr() { 
    return static_cast<T*>(&memory[0]); 
} 

現在我知道,有問題這一點,但爲了使代碼簡稱中我們將假設延遲::構造討論的目的()是在對象超出範圍之前總是調用它。

這就是說,這樣做總是一定安全嗎?或者可以在一些奇怪的角落情況下與其他瘋狂的多個虛擬繼承可以std :: uint8_t [sizeof(T)]沒有分配足夠的空間?

+8

'std :: uint8_t [sizeof(T)]'將始終有足夠的空間。但是......它可能並不總是有正確的對齊方式('std :: aligned_storage'可以幫助那裏)。 –

+0

'uint8_t'是**可選**。使用'uint_least8_t'或'uint_fast8_t';他們將永遠存在。 –

+0

@Pete Becker:是的,但是你知道任何沒有8位整數類型的平臺嗎?另外,我知道在某些平臺上uint_least8_t和uint_fast8_t都是爲了提高效率而對int進行typedef,這可能意味着300%的內存開銷。 'std :: uint8_least8_t [sizeof(T)/ sizeof(std :: uint_least8_t)+((sizeof(T)%sizeof(std :: uint_least8_t)!= 0)?1:0)]'工作,但是一點點醜陋的我的口味...... –

回答

12

R. Martinho Fernandes擊敗了我!使用

typename std::aligned_storage<sizeof(T)>::type memory; 

你很好走。有關詳細信息,請參閱here


由於我們的評論員小組指出,默認對齊方式始終是足夠的,但可能是嚴格比所需的類型(所以你浪費額外填充空間)。您可以通過明確指定來避免這種情況:

typename std::aligned_storage<sizeof(T), alignof(T)>::type memory; 
+0

哈哈,一會兒你就犯了忘記':: type'的常見錯誤:P –

+0

you caught me; D – Useless

+2

'aligned_storage '?沒什麼大不了的,但是在'T'不需要默認(最大)對齊的情況下可以節省填充。 –

相關問題