FBString 的小字符串优化是否依赖于未定义的行为?
Does FBString's small string optimization rely on undefined behavior?
Facebook的fbstring_core类使用本演讲中描述的"小字符串优化",其中类数据成员的存储 -Char*
,size
和capacity
- 将被重新用于存储字符数据,如果字符串足够小。用于区分这些情况的标志位位于"存储的最右侧字符"中。我的问题是,根据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 数组。
相关文章:
- 如何定义依赖于参数包转换的函数的返回类型
- FBString 的小字符串优化是否依赖于未定义的行为?
- 使用 libpthread 在共享库中未定义的行为,但不将其作为依赖项在 ELF 中
- 如何转发声明依赖于变量定义的类,而变体定义又依赖于模板化类?
- 如何定义具有依赖于符号调试的参数的函数
- 如果 LTO 中的代码依赖于其构造的副作用,是否允许 LTO 删除未使用的全局对象?
- 依赖GCC/LLVM的"-fexceptions"在技术上是未定义的行为吗?
- gmp 的 libgmp.so 有哪些依赖关系?我不断收到未定义的引用
- g++ 未定义的引用,尽管符号存在于 *.so 文件中
- 如何从同一个头文件中定义 2 个类,而一个类依赖于另一个类
- 在全局命名空间中重载不依赖于用户定义类型的标准定义类型的运算符是否格式正确?
- 构建不依赖于MSVCR120.DLL的自定义英特尔 MKL DLL
- 如何定义依赖于模板参数的类型定义
- 链接自身依赖于静态库的静态库时未定义的引用
- 依赖VS2010中静态编译的库时未定义的符号
- 此代码是否依赖于函数调用顺序未定义的行为
- void指针之间的比较,它是定义的还是依赖于编译器的
- 对依赖于参数的查找和友元函数定义的混淆
- 依赖于实现的行为和未定义的行为之间有什么区别吗
- 使用"std::conditional_t"定义依赖于其模板参数的类"typedef"