为啥在 GCC 5.1 中仍然启用 COW std::string 优化?

Posted

技术标签:

【中文标题】为啥在 GCC 5.1 中仍然启用 COW std::string 优化?【英文标题】:Why is COW std::string optimization still enabled in GCC 5.1?为什么在 GCC 5.1 中仍然启用 COW std::string 优化? 【发布时间】:2015-07-05 08:39:58 【问题描述】:

根据 GCC 5 发布更改页面 (https://gcc.gnu.org/gcc-5/changes.html):

默认启用新的 std::string 实现,使用小字符串优化而不是写时复制引用计数

我决定检查一下,写了一个简单的程序:

int main()

    std::string x"blah";
    std::string y = x;
    printf("0x%X\n", x.c_str());
    printf("0x%X\n", y.c_str());
    x[0] = 'c';
    printf("0x%X\n", x.c_str());
    printf("0x%X\n", y.c_str());

结果是:

0x162FC38
0x162FC38
0x162FC68
0x162FC38

请注意,x.c_str() 指针在 x[0] = 'c' 之后发生了变化。这意味着内部缓冲区在写入时被复制。因此,COW 似乎仍在工作。为什么?

我在 Ubuntu 上使用 g++ 5.1.0。

【问题讨论】:

我猜你的发行版上的 gcc 配置不同于默认配置以保持 ABI 兼容性。 你是对的。我用 -D _GLIBCXX_USE_CXX11_ABI 编译它,现在它按预期工作(没有 COW 也没有动态内存分配,所以很明显 SSO 正在使用中)。 【参考方案1】:

某些发行版故意偏离 FSF GCC 选择以默认使用新的 ABI。 Here's an explanation of why Fedora 22 deviates from upstream GCC like that.总之:

在一个程序中,最好不要将新旧 ABI 混在一起,而是选择一个并坚持下去。如果程序的某个部分采用与程序的另一部分不同的类型的内部表示,事情就会中断。

因此,如果使用任何使用旧 C++ ABI 的 C++ 库,那么使用该库的程序也应该使用旧 C++ ABI。

因此,如果使用任何使用 GCC 4.9 或更早版本构建的 C++ 库,则使用该库的程序也应该使用旧的 C++ ABI。

Fedora 22 仍然提供(或提供?)大量使用 GCC 4.9 构建的库,因为在 Fedora 22 发布之前没有足够的时间使用 GCC 5.1 重新构建它们。为了允许程序使用这些库,GCC 默认切换到旧的 ABI。

据我所知,GCC 5 还不是 Ubuntu 中的默认编译器(但很快就会成为),所以如果它作为额外安装提供,那么来自 Fedora 的相同参数也适用于 Ubuntu。

【讨论】:

以上是关于为啥在 GCC 5.1 中仍然启用 COW std::string 优化?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 std::map emplace 需要 gcc 上的复制构造函数?

为啥 std::array::size constexpr 具有简单类型(int,double,...)而不是 std::vector (GCC)?

为啥在将 msys gcc 从 9.2 更新到 10.1.0 后我的所有 std 命名空间都损坏了

为啥 MinGW 中仍然没有 std::thread、std::promise 和 std::future? win32中promise和futures的替代方案是啥?

在 Windows 上默认启用 GCC 编译器 C++11 标志

gcc std::unordered_map 实现速度慢吗?如果是这样 - 为啥?