转自:http://hi.baidu.com/yu_xiyan/blog/item/55876a09c906289ed0581bb1.html
先来看看我下面的这段代码 使用上有什么问题: m_WeatherZone = "北京";
CString WeatherInfo = "";
CString Weatherglass= ""; ...... 眼尖的你一定发现问题了吧,其实是我在写代码的时候太着急了 忘记了ReleaseBuffer()..... 下面就来详细探讨下GetBuffer 和 ReleaseBuffer 的原理吧~~~~
LPTSTR CString::GetBuffer(int nMinBufLength) if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength) { } // return a pointer to the character storage for this string
返回值: 可以基于GetBuffer返回的指针,对缓冲进行操作,从而修改CSting的内容。
由上可知,在确定对CString对象当前缓存的操作不会越界的前提下,不必指定GetBuffer的参数,之后对CString的操作都是在当前缓存上进行的;而如果可能造成越界,则必须指定一个值,此时,CString会在内部重新申请一块缓存,作为新的当前缓存。
void CString::ReleaseBuffer(int nNewLength) if (nNewLength == -1) ASSERT(nNewLength <= GetData()->nAllocLength);
ReleaseBuffer的作用只是负责消除多余的缓存内容,比如通过GetBuffer(100)申请了100个字符的空间,但后续只使用了其中的50个,则此时调用ReleaseBuffer()就会将未使用的50个空间释放掉。它并不是说释放掉通过GetBuffer分配的全部缓存空间(实际上,CString目前占用的空间在CString对象释放的时候才由CString对象自动负责释放)。 同时 ReleaseBuffer还有一个很重要的作用,就是“ GetData()->nDataLength = nNewLength;”
SO.. 1)不管是用哪种GetBuffer获得的缓存,在CString对象销毁的时候,这些缓存都会自动销毁。
但使用时需要注意以下问题: 如果要保存的内容不是以0结尾, 比如是读取文件数据, 则GetBuffer参数如果大于文件长度时, ReleaseBuffer参数一定要为文件长度(如果GetBuffer参数为文件长度的话不存在问题, ReleaseBuffer参数可以为默认-1)!
通过以上学习我明白啦~ 没有经过releaseBuffer的时候虽然我已经分配了内存拷贝了值,但是 WeatherZone 、WeatherInfo、Weatherglass 的长度都还是老样子 是0呢,所以做CString的+运算 得到的值就是“” 。 CString s="hello";
LPTSTR ps=s.GetBuffer();
strcpy(ps,"hi");
s.ReleaseBuffer();
此时调用s.GetLength()获取的值是2,正确无误。但如果注释掉s.ReleaseBuffer()这一行,s.GetLength()获取的值则是5,哈哈,错了。
怎么会这样呢,我们来看看MFC中ReleaseBuffer的代码:
void ReleaseBuffer( int nNewLength = -1 )
{
if( nNewLength == -1 )
{
nNewLength = StringLength( m_pszData );
}
SetLength( nNewLength );
}
很明显ReleaseBuffer只有一个作用,就是更新字符串的长度。CString内,GetLength获取字符串长度并不是动态计算的,而是在赋值操作后计算并保存在一个int变量内的,当通过GetBuffer直接修改CString时,那个int变量并不可能自动更新,于是便有了ReleaseBuffer。
其实,计算长度还能用strlen(),这个就算不ReleaseBuffer也不会出错,但如果不ReleaseBuffer,在+=这种赋值时字符串很可能会跟想要得到的不同。 |