15.string实现的多样性

(本章并未完全理解 建议结合More Effective C++ 29 写一个带有引用计数的string类以加深认识)

前言

</br>
sizeof(string)返回多少?不同的实现得到的答案不同。有的string大小等价于char*,而有的则是它的7倍大小。


string的内部组成

每一个string的实现都容纳了以下信息:

  • 字符串大小(size)
  • 该字符串所需的内存容量(capacity)
  • 字符串的值

另外,它们可能含有

  • allocator的拷贝
  • 值的引用计数

不同的string实现以不同的方式把这些信息放在一起,为了证明此言非虚,下文给出了string的四种实现


具体实现

Implement A

image_1can0lrfspfg12ulrsh1f66nu59.png-28.3kB
在实现A中,每个string有4个部分,配置器拷贝,大小,容量,以及一个指针。该指针指向引用计数以及字符串值的缓冲区。如果使用默认allocator,该实现的size是指针的四倍,而自定义allocator的话则会变得更大一些。

Implement B

image_1can0qdv7lmfirra5r1vcbhasm.png-32.4kB
实现B的string对象和内置指针一样大(这里假定使用的是默认allocator),因为其内存结构中确实只包含一个指针。该指针指向的对象包含字符串的大小、容量和引用计数,以及容纳字符串值的动态分配缓冲区的指针。对象也包含在多线程系统中与并发控制有关的一些附加数据。我们把这些数据标注为“other”.

Implement C

image_1can120f91jpa1sh91goa1j7a115113.png-22.7kB
因为与allocator无关,实现C的大小总是等价于指针,X的部分是一些关于值可共享性的数据。(详见More Effective C++ 29)

Implement D

image_1can16lj2647uae1g5gkrc1muo1g.png-43.1kB
实现D的大小是指针的7倍。该实现没有使用引用计数,但每个srtring包含了一个最多可以表现15个字符的内部缓冲区。所以小字符串可以直接保留在对象中,如果大于15,则缓冲器的第一部分变成一个指向动态分配位置的指针,字符串的值存放于该内存中。(不可避免地浪费了一部分内存)


不同实现下的动态分配

1
string("abc");

当写下上述的表达式,我们可以清楚判断出D没有作动态分配,AC则做了一次,B则作了两次(分配对象,分配对象所指的字符缓冲)