FBString 的小字符串优化是否依赖于未定义的行为?



Facebook的fbstring_core类使用本演讲中描述的"小字符串优化",其中类数据成员的存储 -Char*sizecapacity- 将被重新用于存储字符数据,如果字符串足够小。用于区分这些情况的标志位位于"存储的最右侧字符"中。我的问题是,根据C++11标准,通过从未实际编写的bytes_工会成员访问这些位是否构成未定义的行为?访问不活跃的工会成员和未定义行为的答案?建议是的。

以下摘录包含这些成员的声明以及用于确定此优化是否有效的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 中定义的行为?

这不仅看起来像 UB,而且非常没有必要,因为bytes_的唯一用途似乎是读取this的最后一个字节,这可以在没有 UB 的情况下完成:

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

这要归功于 C++ 中的特殊豁免,它允许将对象重新解释为 char 数组。

最新更新