在了解SBO,先来看看这道题:

s1 和 s2 ,谁更大?
在刚学习C++string,就容易陷入误区,觉得s2更大,因为它有数据。
但数据真的存储在string本身吗?并不是,它存储在一片堆空间内,由stirng内部的指针指向该空间 我们之前实现了简单string,其底层是_str,_size,_capacity 按照指针是4/8字节,整型是4字节
那答案会是12 / 16 吗?

答案是28 ,两个都是28 (VS2019 , 32位系统下) 那么这是为什么?通过VS编译器我们可以发现:

如图,看右边可以发现,其底层多了一个字符串数组:_Buf ,16个字符的字符串数组,可存储有效字符数为15

一旦字符串存入的有效字符数大于15,_Buf存不下了,就会转到_Ptr 内
这就是SBO 小对象优化

SBO本质是以空间换时间。 对象比较小时,就不去堆上开空间,存在_Buf 上 比去堆上开空间更省时间,缺点是可能浪费空间。
如果对象太大 ,就在堆上开空间,并用_Ptr 指向该空间。不会两边都存一点,只会选择一边存储
因此,如果有SBO就需要判断字符串存在哪,有效字符数 >=15 就是存堆空间上,小于15 就是存_Buf 上
写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。
引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,语言可能有点抽象,看图理解:

就是这片空间的使用者,每多一个,引用记数就+1,s1构造时,引用记数变成1 ,s2拷贝构造的浅拷贝,使s2也指向这空间,那引用记数变成2
也就是说,引用记数是用来避免多次析构的
当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源(空间), 如果计数为1,说明该对象是资源的最后一个使用者,那他就负责这片资源的析构,释放资源;否则就不能释放,因为还有其他对象在使用该资源(重复析构)
有了上图的解释,相信这句话就好理解很多。
现在我们来了解写时拷贝。写时拷贝,那就是 在写的时候才拷贝

如图,s2,s1都指向同一片资源 "hello world"

如果此时我们要修改资源,那就会使s2也被修改,那写时拷贝的作用就来了:如果引用记数是1,那就直接写(修改
如果引用记数不是1,那就得老实深拷贝

那最终还是要深拷贝,为什么这么麻烦,还搞引用记数?
其实这就是在赌你不需要深拷贝。因为深拷贝的代价很大,(早年编译器不优化深拷贝时)需要来回释放开辟空间,如果你不需要深拷贝,浅拷贝能完成,那就不深拷贝。实在不行再深拷贝。这样提高了效率,不需要干什么都深拷贝。
在下面3点,引用记数就很麻烦,甚至不好:

现阶段还理解不了,目前了解
string完结,后面会开始讲STL:vector ,感谢支持