std::string SSO(Small String Optimization)详解
请解释 std::string 的小字符串优化(SSO)原理,SSO 缓冲区大小通常是多少?SSO 对移动语义和赋值操作有何影响?如何检测一个实现是否使用 SSO?
回答
屠龙少年
SSO 原理:std::string 内部存储一个固定大小的缓冲区(在栈上),当字符串长度 ≤ 该缓冲区大小时,不进行堆分配。
SSO 缓冲区大小:取决于实现:
- GCC libstdc++:15 字节(sizeof(string) = 32)
- Clang libc++:22 字节(sizeof(string) = 24)
- MSVC:16 字节(sizeof(string) = 32)
数据结构示意(libstdc++):
// sizeof = 32 bytes
class string {
char* _M_data; // 8 bytes:指向堆或本地缓冲区
size_t _M_size; // 8 bytes
union {
char _M_local_buf[16]; // SSO 缓冲区
size_t _M_capacity; // 堆分配时存容量
};
};
SSO 影响:
- 移动语义:SSO 字符串移动时可能需要拷贝缓冲区(vs 堆分配字符串只交换指针)。
- 赋值:短字符串赋值(memcpy 大小)快于堆分配/释放。
- 缓存友好:短字符串与 string 对象在同一缓存行。
检测 SSO:
auto s = std::string(10, 'a');
// 取 &s[0] 和 &s 比较地址
// 若地址在栈上(接近 &s 地址)则使用了 SSO
最佳实践:利用 SSO 减少短字符串的堆分配开销。但过长字符串仍需堆。