先看一段代码:
#include <atlstr.h>
//测试CString
int main(int argc, _TCHAR* argv[])
{
CStringA strTemp = "555";
//这里输出为3,不包含结束符
printf("str=%s,len=%d\n",strTemp.GetBuffer(),strTemp.GetLength());
LPSTR lpStr = strTemp.GetBuffer(10);
//这里输出为3,因为对GetBuffer的返回值进行了操作,未调用ReleaseBuffer,GetLength()返回结果将不正确
strcpy(lpStr,"666666");
printf("str=%s,len=%d\n",strTemp.GetBuffer(),strTemp.GetLength());
strTemp.ReleaseBuffer();
//由于调用了ReleaseBuffer,GetLength()的返回结果就为6
printf("str=%s,len=%d\n",strTemp.GetBuffer(),strTemp.GetLength());
system("pause");
return 0;
}
运行结果:
ReleaseBuffer源码:
void ReleaseBuffer(_In_ int nNewLength = -1)
{
//默认ReleaseBuffer参数为-1,表示重新计算字符串长度
if( nNewLength == -1 )
{
int nAlloc = GetData()->nAllocLength;
//相当于调用的strnlen
nNewLength = StringLengthN( m_pszData, nAlloc);
}
SetLength( nNewLength );
}
通过这个例子再结合ReleaseBuffer的源码可以看出,CString的字符串长度并非实时计算的,而是有个内部变量保存了这个长度,通过调用ReleaseBuffer可以更新这个长度值。
也就是说假如我们修改了来自GetBuffer返回的指针所指向的空间,那么我们就需要调用ReleaseBuffer,否则这个CString对象在计算+=等重载运算符时,由于没有正确的长度值,得到的结果往往是错误的!当然如果未修改该指针指向的空间,则不需要调用ReleaseBuffer()。
下面是权威,官方文档说明:
If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before you use any other CSimpleStringT member methods.
这里的CSimpleString是CString的基类
下面再简单提下GetBuffer(),该函数有两种形式
PXSTR GetBuffer(
int nMinBufferLength
);
PXSTR GetBuffer();
可以简单的认为,GetBuffer()返回的就是当前的CString内部字符串指向空间的指针,GetBuffer(int)也一样,不过当传入的值大于当前CString的空间时,CString会重新分配一块更大的空间并拷贝原值过去,再返回指向该新空间的指针,当然实际情况更为复杂一些,比如存在引用计数之类的,不过基本原理就是这样的,理解了原理,用起来也就更放心了。