我正在编写一些C++ 11代码,这些代码对其性质的假设std::string
是有效的,但代表了在C++ 11中改变的行为.在早期,libstdc ++的basic_string
实现符合98/03的要求,但不符合更严格的C++ 11要求.
据我了解,libstdc ++修复了问题basic_string
.问题是人们使用的库有许多版本没有实现此修复.而且我的代码可能会以许多不愉快的方式无声地失败.
我想有一个static_assert
火,如果用户尝试编译我的图书馆对的libstdc ++的那些不符合的版本.如何检测版本,同样重要的是,我应该查找哪个版本?
新的C++ 11兼容性std::string
是在GCC 5中的新(双)ABI(更改日志的运行时库部分)中引入的.
宏_GLIBCXX_USE_CXX11_ABI
决定是使用旧的还是新的ABI,所以只需检查它:
#if _GLIBCXX_USE_CXX11_ABI
当然这仅限于libstdc ++.
#includestatic_assert(sizeof(std::string) != sizeof(void*), "using ref-counted string"); int main() { }
演示:http: //melpon.org/wandbox/permlink/P8LB79Cy6ASZlKuV
该测试利用了所有已知的std :: lib实现的内部工作,std::string
特别是gcc的实现.
gcc的refcounted string
由一个指向动态分配结构的单个指针组成,该结构包含字符串的大小,容量,引用计数和数据.Scott Meyers对Effective STL中的字符串实现进行了很好的总结,这在2001年的时间框架中是准确的.我相信(我可能会误认为)该书第15项中的"实施C"是gcc的std :: string.
对于短字符串实现(几乎是C++ 11强制要求),a string
不再包含堆栈上的单个指针.Scott的实现D是我们第一次看到那个时代的短串实现.这是VS/Dinkumware string
.它sizeof(string)
本身将包含一些数据缓冲区来保存没有分配的字符串数据.
人们可以掌握这个简短程序的不同实现:
#include#include 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)
哪个是字大小的倍数,然后打印出capacity()
一个空的string
,如果它存在则将是短字符串缓冲区的大小.
这是一个有点不完整的调查:
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 ++上工作.