c++ stl ,如何实现,没有规定,各家有各家的配方,vc2013 stl 中的 string 数据成员简写形式:
class string
{
allocate_proxy * proxy; // 内存申请管理器 4字节
union _Bxty //16个字节
{
char _Buf[16]; // 短字符串保存在这里,
char * _Ptr; // 当使用动态申请内存时new char[n],这个成员指向申请到的内存
char _Alias[16]; // 什么鬼?
} _Bx;
size_type _Mysize; // 字符串长度,不包含'\0' 4字节
size_type _Myres; // 保留的字节数 4字节
}
现在的stl实现,多数都采用 SOO(small object optimization) 技术,即小对象优化技术,对字符串来说,也可称 SSO(small string optimization), 做法是将短串保存在类内存里,超过一定长度的字符串数据,才通过动态申请内存来保存。之所以这样做,是考虑到申请动态内存,开销大,减少动态申请,可以提高程序效率,是典型的以空间换效率的做法,关于SSO, 可参照文章:
https://shaharmike.com/cpp/std-string/
vc2013的string实现,就是基于这样的思想。在 vc2013 中,sizeof std::string 为 28 个字节,从上述得知 , 4+16+4+4 = 28个字节, 注意_Bx._Buf预留了16个字节的,用来保存长度不超过15的短串,这样的短串,直接复制这里,类似:
string x("hello");
等价:
string x;
strcpy(x._Bx._Buf,"hello");
x._Mysize = strlen("hello");
x._Myres = 15;
如果大于15的串,如:
string x("i am big string abcdefghijklm.....................");
等价于:
string x;
x._Bx._Ptr = new char[strlen("i am big string abcdefghijklm.....................")+1]; // 实际可能会多申请一些内存,这里简化了,用多少申请多少
x._Mysize = strlen("i am big string abcdefghijklm.....................");
x._Myres = x._Mysize; // 当申请得多,保留数与字符串长度会不一样
那怎么知道,实际保存的字符串地址在哪里,以下的 string::c_str() 实现可回答这个问题:
const * char string::c_str()
{
if(this._Myres >15) // 是长串,
{
return _Bx._Ptr; // 返回动态申请的地址
}else
{
return _Bx._Buf ; // 是短串,返回本地地址
}
}
可以看出,当长串时,union的16个字节,只用了开始的四个字节有效,来表示动态内存地址,其余12个字节没用,典型的用空间换效率的做法。