C++ string的COW和SSO

还记得书本上的关于深拷贝和浅拷贝的问题吗?

如果自己写的一个类TestClass,采用的是默认的构造函数,或者采用自定义的构造函数(但是没有实现深拷贝)。那么下面的代码:

class TestClass
{
public:
char * p;
};


TestClass a;

TestClass  b(a);

TestClass  c = a;

上诉都是浅拷贝,也就是a.p == b.p == c.p;如果要想深拷贝,必须由你自己用代码实现。


STL中string的情况呢?

首先来看看下面语句的语义(也就是你这样写实际上是想要达到什么目的,或者是大家一看就知道的想要达到的目的):

string str1;

string str2(str1);

string str3 = str1;

上诉的三句实际上是想实现的什么呢?答案是深拷贝。实际上只要是采取上诉的赋值操作符或者是拷贝构造函数,用户都是想实现的是深拷贝。那么作为STL string的开发实现者就必须要实现string拷贝构造函数和=操作符的深拷贝。

但是这里string做了优化,做到对内存管理的优化。

这里不同版本的string采用了不同的方法:COW和SSO

看如下代码:

string str1("123456");
string str2(str1);

printf("%d***************%d +++++++ %d***************%d\n", &str1, str1.c_str(), &str2, str2.c_str());   //1 step

str1[0] = '1';
printf("%d***************%d +++++++ %d***************%d\n", &str1, str1.c_str(), &str2, str2.c_str());   //2 step

如果string采取的是COW的实现方式,那么1 step输出的str1.c_str()和str2.c_str()的值相等,说明str1和str2共享了字符串数组这部分的内存空间。(因为我的VS2010采用的是SSO方式,所以这里不能贴出实际的实验结果)。

但是当str1和str2中有任何一方的数据发生更改的时候,就会发生重新申请内存的操作和拷贝操作(因为两个string数据不一样了,不能再共享了)。

Copy On Write(COW)相当于是把申请内存和拷贝操作往后拖延了,直到不得不这样做时才这样做。这种方法是把导致分配支援的耗时操作往后延迟的方法。可能导致多个延迟操作在后面的某一时间同时需要统一完成(多个string数据同时发生改变),那么会导致后面的某个时间点会出现比较大的累计延迟。可以说有利也有弊。


再看看如下的代码:

string     str1("123456789654464444444461322222222222222222222222222222222222222363333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333331111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");

string str2(str1);

printf("%d***************%d +++++++ %d***************%d\n", &str1, str1.c_str(), &str2, str2.c_str());

str1[0] = '1';
printf("%d***************%d +++++++ %d***************%d\n", &str1, str1.c_str(), &str2, str2.c_str());

运行结果如下:


这是字符串比较长的时候的string申请内存空间的情况。很显然字符串数组(str1.c_str())的地址和string对象的地址差别较大,前者处于堆空间,后者处于函数的栈空间。这种情况一般就是我们所认识的深拷贝了,我们自己写的类的深拷贝也就是这种情况。


再看下面的代码:

string str1("123456");
string str2(str1);

printf("%d***************%d +++++++ %d***************%d\n", &str1, str1.c_str(), &str2, str2.c_str());

str1[0] = '1';
printf("%d***************%d +++++++ %d***************%d\n", &str1, str1.c_str(), &str2, str2.c_str());

运行结果是:


从结果可以看出&str1和str1.c_str()的值比较接近,他们都属于函数的栈空间。这就说明此时的string内部的字符串数组没有去堆上申请空间,而是足够小的字符串直接存在了对象本身的栈内存中。所以这种情况str1和str2是没有共享内存的,所有的数据都在各自的对象中。这在语义上是深拷贝,但是和我们自己实现的深拷贝不一样。这就是有的STL string版本实现的(small string optimization)SSO方式。VS2010就是采用的SSO方式。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值