(本章并未完全理解 建议结合More Effective C++ 29 写一个带有引用计数的string类以加深认识)
前言
</br>
sizeof(string)返回多少?不同的实现得到的答案不同。有的string大小等价于char*,而有的则是它的7倍大小。
string的内部组成
每一个string的实现都容纳了以下信息:
- 字符串大小(size)
- 该字符串所需的内存容量(capacity)
- 字符串的值
另外,它们可能含有
- allocator的拷贝
- 值的引用计数
不同的string实现以不同的方式把这些信息放在一起,为了证明此言非虚,下文给出了string的四种实现
具体实现
Implement A
在实现A中,每个string有4个部分,配置器拷贝,大小,容量,以及一个指针。该指针指向引用计数以及字符串值的缓冲区。如果使用默认allocator,该实现的size是指针的四倍,而自定义allocator的话则会变得更大一些。
Implement B
实现B的string对象和内置指针一样大(这里假定使用的是默认allocator),因为其内存结构中确实只包含一个指针。该指针指向的对象包含字符串的大小、容量和引用计数,以及容纳字符串值的动态分配缓冲区的指针。对象也包含在多线程系统中与并发控制有关的一些附加数据。我们把这些数据标注为“other”.
Implement C
因为与allocator无关,实现C的大小总是等价于指针,X的部分是一些关于值可共享性的数据。(详见More Effective C++ 29)
Implement D
实现D的大小是指针的7倍。该实现没有使用引用计数,但每个srtring包含了一个最多可以表现15个字符的内部缓冲区。所以小字符串可以直接保留在对象中,如果大于15,则缓冲器的第一部分变成一个指向动态分配位置的指针,字符串的值存放于该内存中。(不可避免地浪费了一部分内存)
不同实现下的动态分配
1 | string("abc"); |
当写下上述的表达式,我们可以清楚判断出D没有作动态分配,AC则做了一次,B则作了两次(分配对象,分配对象所指的字符缓冲)