最近写的一个程序,为了使接口简便,在返回字符串的时候不得已使用了stl::string,但是又担心如果此方法被频繁调用,可能会导致性能问题,于是尝试用一些底层机制去优化stl::string。
stl::string是怎么实现的呢?脑海中有一个猜想,首先就是这样:
class string
{
private:
char* m_str;
int m_len;
};
为了验证这个想法,于是用sizeof(string)将类型的长度打出来看看…………结果让人大跌眼镜,还要我不戴眼睛!在GCC中,sizeof(string)=4。怎么可能嘛?如果就四个字节,哪里放长度信息呢?
再次输出更多信息来验证:
string str = "abcde";
printf("addr=%08x, this=%08x, str=[%s]/n", (unsigned int)str.c_str(), *((unsigned int*)&str), str.c_str());
string自身的四个字节存储的内容竟然就是所指向的字符串的指针!!!
难道?难道,string在GCC中的实现,就仅仅只是char*,如果调用str.length(),就是悄悄去调用strlen()?
再写一个输入内存的16进制字符串的函数PrintHex(),用这个函数将内存中的信息打印出来,实现如下:
打印一下内存的信息试试:
string str="abcde";
PrintHex(((char*)str.c_str())-20, 40);
分析16进制字符串,大概明白点string的内部了,看懂的部分大约是这样的:
struct string_buffer
{
int Length;
int Capacity;
int unknown;
char Content[_Capacity]; // _Capacity = Capacity
};
而string只是指向这样一个内存块的content部分的指针。分配多个string,就会发现这些内存块隔得很近。
以上分析说明:
1、string只是指向字符串池中内容部分的一个指针;(将string作为参数或者返回值,性能都很高,等同于const string&这样的参数)
2、字符串池的块中缓存了长度和预留空间等信息,所以,不要使用C的字符串函数来操作string的任何内容,结果可能不一致。
最后,试试在VC中打印:sizeof(string),天哪!28个字节!微软的STL实现,不敢恭维啊!
stl::string是怎么实现的呢?脑海中有一个猜想,首先就是这样:
class string
{
private:
char* m_str;
int m_len;
};
为了验证这个想法,于是用sizeof(string)将类型的长度打出来看看…………结果让人大跌眼镜,还要我不戴眼睛!在GCC中,sizeof(string)=4。怎么可能嘛?如果就四个字节,哪里放长度信息呢?
再次输出更多信息来验证:
string str = "abcde";
printf("addr=%08x, this=%08x, str=[%s]/n", (unsigned int)str.c_str(), *((unsigned int*)&str), str.c_str());
string自身的四个字节存储的内容竟然就是所指向的字符串的指针!!!
难道?难道,string在GCC中的实现,就仅仅只是char*,如果调用str.length(),就是悄悄去调用strlen()?
再写一个输入内存的16进制字符串的函数PrintHex(),用这个函数将内存中的信息打印出来,实现如下:
void
PrintHex(
char
*
Buffer,
int
Size, FILE
*
fp
=
stdout)
{
fprintf(fp, "===================================================== ");
char* p = NULL;
int i;
for (i=0, p = Buffer; i<Size; i++, p++)
{
fprintf(fp, "%02x ", (unsigned char)*p);
if (i%16==15)
{
fprintf(fp, " ");
}
}
fprintf(fp, " ===================================================== ");
}
{
fprintf(fp, "===================================================== ");
char* p = NULL;
int i;
for (i=0, p = Buffer; i<Size; i++, p++)
{
fprintf(fp, "%02x ", (unsigned char)*p);
if (i%16==15)
{
fprintf(fp, " ");
}
}
fprintf(fp, " ===================================================== ");
}
打印一下内存的信息试试:
string str="abcde";
PrintHex(((char*)str.c_str())-20, 40);
分析16进制字符串,大概明白点string的内部了,看懂的部分大约是这样的:
struct string_buffer
{
int Length;
int Capacity;
int unknown;
char Content[_Capacity]; // _Capacity = Capacity
};
而string只是指向这样一个内存块的content部分的指针。分配多个string,就会发现这些内存块隔得很近。
以上分析说明:
1、string只是指向字符串池中内容部分的一个指针;(将string作为参数或者返回值,性能都很高,等同于const string&这样的参数)
2、字符串池的块中缓存了长度和预留空间等信息,所以,不要使用C的字符串函数来操作string的任何内容,结果可能不一致。
最后,试试在VC中打印:sizeof(string),天哪!28个字节!微软的STL实现,不敢恭维啊!