2017-08-26 88 views
8

Facebook的fbstring_core類使用this talk描述的「小字符串優化」,其中對於該類的數據成員存儲 - 一個Char*sizecapacity - 將被重新用於存儲字符數據,如果該字符串是足夠小。用於區分這些情況的標誌位位於「存儲器的最右側字符」中。我的問題是,通過bytes_聯合成員訪問這些比特是否構成未定義的行爲? Accessing inactive union member and undefined behavior?的答案表明它是。FBString的小字符串優化是否依賴未定義的行爲?

以下摘錄包含這些成員的聲明和category()成員函數,用於確定此優化是否有效。

typedef uint8_t category_type; 

    enum class Category : category_type { 
     isSmall = 0, 
     isMedium = kIsLittleEndian ? 0x80 : 0x2, 
     isLarge = kIsLittleEndian ? 0x40 : 0x1, 
    }; 

    Category category() const { 
     // works for both big-endian and little-endian 
     return static_cast<Category>(bytes_[lastChar] & categoryExtractMask); 
    } 

    struct MediumLarge { 
     Char * data_; 
     size_t size_; 
     size_t capacity_; 

     size_t capacity() const { 
     return kIsLittleEndian 
      ? capacity_ & capacityExtractMask 
      : capacity_ >> 2; 
     } 

     void setCapacity(size_t cap, Category cat) { 
     capacity_ = kIsLittleEndian 
      ? cap | (static_cast<size_t>(cat) << kCategoryShift) 
      : (cap << 2) | static_cast<size_t>(cat); 
     } 
    }; 

    union { 
     uint8_t bytes_[sizeof(MediumLarge)]; // For accessing the last byte. 
     Char small_[sizeof(MediumLarge)/sizeof(Char)]; 
     MediumLarge ml_; 
    }; 

看來,這實現依賴於使用「雙關式」訪問實際上可能是size_t capacity_成員的一部分,一個字節。從上面鏈接的問題的答案中,我收集到這在C99中定義的行爲,但而不是在C++ 11?

+1

總是允許訪問任何簽名的「char」。 – o11c

+1

Boost中導致bug的一些類似代碼:https://svn.boost.org/trac10/ticket/12183 –

+0

@ o11c:是否將uint8_t定義爲char類型的別名,但?使用''unsigned char''似乎更安全。 –

回答

11

不僅那些看起來UB,這是完全沒有必要的,因爲bytes_的唯一用途似乎是閱讀的this最後一個字節,它可以在不UB做到:

reinterpret_cast<const char*>(this)[sizeof(*this) - 1] 

這這要歸功於C++中的特殊豁免,它允許將對象重新解釋爲字符數組。

相關問題