2015-03-25 62 views
3

該問題與this post有關。使用指針轉換來存儲/轉換值:我打破嚴格的別名規則嗎?

一些權威用戶聲稱以下代碼打破strict aliasing rules

#include <boost/static_assert.hpp> 

template <typename T> 
struct MyType { 

    private: 
    T data; 

    public: 
    template <typename U> 
    operator U() { 
     BOOST_STATIC_ASSERT_MSG(sizeof(U) == sizeof(T),"Trying to convert to data type of different size"); 
     return *((U*) &data); 
    } 

    template <typename U> 
    NeonVectorType<T>& operator =(const U& in) { 
     BOOST_STATIC_ASSERT_MSG(sizeof(U) == sizeof(T),"Trying to copy from data type of different size"); 
     data = *((T*) &in); 
     return *this; 
    } 
} 

不過,我從來沒有使用指針數據,而我從來沒有分享它的指針,所以我不能看到包含在變量值如何更改,恕不編譯器意識到這是發生。我的印象是,也許我打破了一些規則,但不是嚴格的別名...

注意:我不知道這有多重要,但我的編譯器(gcc 4.9)不會發出警告。

+0

我懷疑你混淆了嚴格的別名規則與指針別名,這是一種不同的別名形式。 – molbdnilo 2015-03-25 10:37:52

回答

2

*((U*) &data)將違反嚴格的別名,如果這是一個reinterpret_cast和類型U不允許別名T類型。允許的類型出現在this list

該規則涉及both reading and writing

Here是一篇很好的文章,解釋了規則背後的一些基本原理。

由於主嚴格別名線程上指出的那樣,你可以使用memcpy作爲變通,例如:

U u; 
memcpy(&u, &data, sizeof u); 
return u; 

,並在其他功能

memcpy(&data, &in, sizeof data); 

注意類的原始字節副本類型受到一些限制(我認爲類必須是POD,並且您最好確定它們具有相同的佈局)。

+0

如果類型不兼容(U無法替代T),爲什麼編譯器不會觸發警告?難以爲編譯器檢索到這些信息嗎? – Antonio 2015-03-25 10:44:52

+0

這不是很好的檢測這種違規行爲。正如在我鏈接的頁討論的,之後的碼是可識別的 – 2015-03-25 10:50:29

1

不過,我從來沒有使用指針數據[...]

標準比這更一般的語言; [basic.life]/7具有:

[...]的指針 指向原始對象,即稱爲原始對象的引用,或原始 對象的名稱[ ...]

在你operator=你使用T類型的左值寫入data,並在operator U你使用U讀它類型的指針;其中UT是不相關的,而不是字符類型,這是UB。

只需使用memcpy。這是保證工作,它很有效(試試)!

+0

實際上,memcpy的被優化了,併產生完全相同的彙編代碼,可能會出現混疊通長! – Antonio 2015-03-25 10:58:03

相關問題