dre*_*rbs 10 c++ undefined-behavior type-punning c++11
Facebook的fbstring_core类使用中所描述的"小字符串优化" 这次谈话,其中的类的数据成员的存储-一Char*,size和capacity-将被重新用于存储字符数据字符串是否足够小.用于区分这些情况的标志位位于"存储器的最右边的字符"中.我的问题是,是否通过bytes_union成员访问这些位(实际上从未编写过)是否构成了C++ 11标准的未定义行为?访问非活动联盟成员和未定义行为的答案?表明它是.
以下摘录包含这些成员的声明以及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_;
};
Run Code Online (Sandbox Code Playgroud)
看起来这个实现依赖于使用"类型双关语"来访问实际上可能是size_t capacity_成员一部分的字节.从问题的答案上面链接,据我了解,这是在C99中定义的行为,而不是在C++ 11?
Joh*_*nck 13
这看起来不仅仅是UB,它是非常不必要的,因为它的唯一用途bytes_似乎是用于读取最后一个字节this,这可以在没有UB的情况下完成:
reinterpret_cast<const char*>(this)[sizeof(*this) - 1]
Run Code Online (Sandbox Code Playgroud)
这要归功于C++中的特殊豁免,它允许将对象重新解释为char数组.