string对象大小问题

库中string类的底层还有一些小问题

s2后给的字符串不是存到string对象本身的空间上面的,而是存在该对象指向的堆空间上,所以这里s1对象和s2对象的大小是没有任何区别的。根据其成员变量,理论上在 32 位系统中,char* 和size_t占 4 字节,总大小为 4 + 4 + 4 = 12字节,在 64 位系统中,char* 占 8 字节,size_t占 8 字节,因此总大小为 8(_str) + 8(_size) + 8(_capacity) = 24字节。 然而实际在32位系统下,这里的大小是28字节

二、小对象优化(SBO)技术

这里看一下底层结构

这里字符个数小于等于15的时候就会存到_Buf当中,大于15的时候,_Buf就丢弃不用了,而是存到_Ptr指向的空间当中

在这里插入图片描述

在这里插入图片描述

这是一种通用的内存管理设计技术,叫做小对象优化(SBO),在大量的开辟小块空间的时候,不仅会有内存碎片的问题,而且效率也是不够高,SBO本质上是一种以空间换时间的处理方式,当对象比较小的时候就会在对象中存一个_Buf(在对象内部预留固定大小的缓冲区直接存储小对象数据,_Buf是一个小数组,在对象开数组是比堆上开数组快的)而不去堆上开空间(减少动态内存分配开销和碎片化问题),这种处理方式通常用于在堆上开空间的结构

当对象比较大的时候就会再用另外一个数组_Ptr,而不会两个数组各存一部分,若各存一部分像用c_str都无法返回给值,这样就浪费了一个数组的空间了

在这里插入图片描述

在这里插入图片描述

所以整个代码访问数据的位置就要判断数据到底放在哪里,字符串_size小于16放_buff当中,大于等于16放_str当中。此时对其再算,在32位平台下整个对象空间就是28字节了

三、写时拷贝(COW)技术

VS一贯采用该技术来进行内存管理优化,Linux系统下的早期的G++是采用另外一种方案(COW COPY - ON - WRITE):引用计数,其库中string设计的时候默认的拷贝是进行浅拷贝

在这里插入图片描述

在这里插入图片描述

两个对象指向同一块空间,该空间的引用计数为2,之后进行析构(例如先析构s2),编译器就会先看引用计数,发现引用计数为2,说明还有其他对象一同管理这块空间,此时就会减减计数(1),之后s1进行析构,再减减计数(0),此时计数为0就说明s1就是最后一个管理这块空间的对象,此时再释放空间

在这里插入图片描述

在这里插入图片描述到这里只解决了析构多次的问题,浅拷贝还有另外一种问题,两个对象指向同一块空间时,一个对象的修改会影响另一个对象,这里就还有一种操作叫做写时拷贝,该操作也是依托于引用计数,若进行写的时候(例如:s1[0]=‘x’)就会去检查引用计数,若引用计数为1才会进行写的操作,此时只有一个对象指向这块空间,若引用计数不是1还要开一块空间拷贝数据,之后原空间计数减减,新空间也会有计数(为1),此时再进行s1[0]='x’的操作就没有问题了



 

更多推荐