std::string 的三种主要实现的非正式比较 - The Old New Thing

主要观点:比较了std::string的三种主要实现(gcc、msvc、clang)在一些常见操作上的复杂度及其他特性,包括检测字符串大小、获取数据、获取大小、判断是否为空、获取容量等方面,还提及了静态初始化以及混合状态等情况,并总结在表格中。
关键信息:

  • gcc 实现中string结构体包含char* ptrsize_t size和联合union { size_t capacity; char buf[16]; }等成员,通过比较ptrbuf判断字符串大小等。
  • msvc 实现中string结构体包含联合union { char* ptr; char buf[16]; }size_t sizesize_t capacity等成员,通过比较capacity和 15 判断字符串大小等。
  • clang 实现中union string包含大字符串结构体struct { size_t capacity; size_t size; char* ptr; } large和小字符串结构体struct { unsigned char is_large:1; unsigned char size:7; char buf[sizeof(large) - 1]; } small等成员,通过测试is_large判断字符串大小等。
  • 比较了三种实现在不同操作上的指令差异及性能优劣,如检测字符串大小的指令不同,获取数据、大小、容量等操作的速度也有差异,且 clang 在内存使用方面有优势,在某些特殊情况下(如静态初始化、shrink_to_fit()等)也有不同表现。
    重要细节:
  • gcc 可通过重新排序成员优化检测字符串大小的指令,但会增加访问ptr的成本。
  • clang 实现中获取data()size()等操作的指令较复杂,通过测试is_large来决定使用大字符串或小字符串的相关成员。
  • msvc 实现中使用容量来检测是否使用小字符串优化,在扩展字符串时append(char)操作有优势。
  • 静态初始化时,gcc 的空字符串包含指针会引入数据段重定位,msvc 和 clang 则无指针且无重定位。
  • 总结表格展示了三种实现在多个方面的特性对比。

更新内容:原文章中 clang 实现的“small/large”位方向有误,导致重新生成代码和新的代码优化结果;之前版本错误地认为shrink_to_fit()在 gcc 上是无操作。

作者信息:Raymond Chen 参与 Windows 进化 30 多年,其网站 The Old New Thing 很受欢迎并出版相关书籍,偶尔在 Windows Dev Docs Twitter 账户上讲故事。

阅读 9
0 条评论