测试 libstdc++ 的版本是否使用 C++11-compliant std::string

Test whether libstdc++'s version uses a C++11-compliant std::string

我正在编写一些 C++11 代码,这些代码对 std::string 的性质做出假设是有效的,但表示在 C++11 中更改的行为。在早期,libstdc++ 的 basic_string 实现符合 98/03 要求,但不符合更严格的 C++11 要求。

据我了解,libstdc++ 已经修复了 basic_string 周围的问题。问题是人们使用的许多版本的库都没有实现此修复。我的代码可能会以许多令人不快的方式默默地失败。

如果用户试图针对那些不一致的 libstdc++ 版本编译我的库,我希望 static_assert 触发。如何检测版本,同样重要的是,我应该查找哪个版本?

在 GCC 5 (Runtime Library Section of the changelog) 中引入了新的 C++11 兼容 std::string 以及新的(双)ABI。

_GLIBCXX_USE_CXX11_ABI决定是使用旧的还是新的ABI,所以检查一下:

#if _GLIBCXX_USE_CXX11_ABI

当然,这仅适用于 libstdc++。

#include <string>

static_assert(sizeof(std::string) != sizeof(void*), "using ref-counted string");

int
main()
{
}

演示:http://melpon.org/wandbox/permlink/P8LB79Cy6ASZlKuV

此测试利用了 std::string 的所有已知 std::lib 实现的内部工作原理,尤其是 gcc 的实现。

gcc 的 refcounted string 由指向动态分配结构的单个指针组成,该结构包含字符串的大小、容量、引用计数和数据。 Scott Meyers 在 Effective STL 中对字符串实现进行了很好的总结,该总结在 2001 年的时间范围内是准确的。我相信(我可能会弄错)那本书第 15 项中的 "implementation C" 是 gcc 的 std::string.

对于短字符串实现(C++11 几乎强制要求),string 不能再由堆栈上的单个指针组成。 Scott 的实现 D 是我们第一次看到那个时代的短字符串实现。这是VS/Dinkumwarestringsizeof(string) 本身将包含一些数据缓冲区来保存没有分配的字符串数据。

你可以了解不同的实现正在用这个简短的程序做什么:

#include <iostream>
#include <string>

int
main()
{
    std::string s;
    std::cout << "word size is           " << sizeof(void*)/sizeof(char) << '\n';
    std::cout << "sizeof string is       " << sizeof(s) << '\n';
    std::cout << "short string buffer is " << s.capacity() << '\n';
}

这会打印出字长,通常为 4 或 8(32 位/64 位),因为至少一个实现 (libc++) 更改了其在该硬件功能上的特性。然后它打印出 sizeof(string) ,它将是单词大小的倍数,然后是空 stringcapacity(),如果存在,它将是短字符串缓冲区的大小.

这里有一份不完整的调查:

gcc/libstdc++ 4.8

word size is           8
sizeof string is       8
short string buffer is 0

gcc/libstdc++ 5.2

word size is           8
sizeof string is       32
short string buffer is 15

clang/libc++ -arch i386 OS X

word size is           4
sizeof string is       12
short string buffer is 10

clang/libc++ -arch x86_64 OS X

word size is           8
sizeof string is       24
short string buffer is 22

VS-2015

word size is           4
sizeof string is       24
short string buffer is 15

在这次调查中,只有 gcc/libstdc++ 4.8 显然没有使用短字符串优化。而且只有 gcc/libstdc++ 4.8 有 sizeof(string) == 1 word。这实际上是本次调查中唯一使用引用计数的实现。

总而言之,这个针对 libstdc++ 的 std::string 的测试不可移植。但根据规范,它不一定是。我们可以利用已知的 gcc 在这方面的发展历史。规范(问题)说它只需要在 gcc 的 libstdc++ 上工作。