针对字符串不同的长度,“编译器”选择不同的优化策略:SSO, eager copy,COW,分别针对短字符串,中等长度字符串,长字符串。不过,现在(2016)的大多数编译器(gcc 4.9.1,vs2008以后,clang++没有测试)都选择SSO.
SSO: small string optimization
eager copy
COW: copy on write
我们看下面这一代码段,编译器(gcc 4.9.1)
string a="hello world";
string b=a;
assert(a.data() != b.data());
if (a.data()==b.data()) //a.c_str() == b.c_str()
cout<<"true"<<endl;
else
cout<<"false"<<endl;
结果输出:false。所以,可以很明显的判断出,现代的gcc编译器已经弃用了COW。而网上的一些讨论,早期的gcc是选用COW技术的。
一、COW
1,一些优点
1)COW能够减少单步操作时由于分配空间及数据复制带来的瞬间延迟
2)在某些条件下,COW能够启动空间优化的作用
不过,对于现代的硬件环境,这两个优点也体现不出优势了。
2,可能的起源
COW早期是用在fork进程中的。Linux在fork时,会让子父进程共享一个进程地址空间。只有当进程要修改地址空间的数据时,才会让子父进程拥有自己的拷贝空间。
3,一些可能的缺陷
由于COw的本质是共享地址空间,那么在多线程环境中,需要处理竞态(data race)
二、代码段中的函数
1,std::string::data和std::string::c_str同义
const char* data() const noexcept;
const char* c_str() const noexcept;
返回一个指针,该指针指向一个字符数组,其内容和string object相同。
示例代码:
// strings and c-strings
#include <iostream>
#include <cstring>
#include <string>
int main ()
{
std::string str ("Please split this sentence into tokens");
char * cstr = new char [str.length()+1];
std::strcpy (cstr, str.c_str());
// cstr now contains a c-string copy of str
char * p = std::strtok (cstr," ");
while (p!=0)
{
std::cout << p << '
';
p = std::strtok(NULL," ");
}
delete[] cstr;
return 0;
}
值得注意的是,str.c_str()返回的是一个临时指针,一般使用strcpy对其操作。当然,也可作为函数中char*的参数,如下:
string s = "Hello World!";
printf("%s", s.c_str());
QAQ,上面的代码段又引入了一个一个函数std::strtok.
2,strtok
char * strtok ( char * str, const char * delimiters );
Split string into tokens。就是把str所指向的字符串,以delimeters中的分隔符,分成一个个子字符串。
值得注意的是,在子序列的调用中,需要给函数传入一个null pointer,以上一个token的末尾作为新的token扫描开始地址。对应者上面的
p = std::strtok(NULL," ");
另外,关于COW的深入探讨,这篇博客比较详细:http://www.cnblogs.com/promise6522/archive/2012/03/22/2412686.html