关于CString的GetBuffer 和 ReleaseBuffer

先来看看我下面的这段代码 使用上有什么问题:

m_WeatherZone = "北京";
m_szWeatherInfo = "多云转晴";
m_szWeatherglass = "23~35度";
......
......
CString WeatherZone = "";
int strLen = this->m_WeatherZone.GetLength();
memcpy(WeatherZone.GetBuffer(strLen),this->m_WeatherZone.GetBuffer(strLen),strLen);

 

CString  WeatherInfo = "";
strLen = this->m_szWeatherInfo.GetLength();
memcpy(WeatherInfo.GetBuffer(strLen),this->m_szWeatherInfo.GetBuffer(strLen),strLen);

 

CString  Weatherglass= "";
strLen = this->m_szWeatherglass.GetLength();
memcpy(Weatherglass.GetBuffer(strLen),this->m_szWeatherglass.GetBuffer(strLen),strLen);

......
......
 CString weather = WeatherZone +" " +WeatherInfo +" "+Weatherglass;
 为啥得带的这个weather 是"  "呢?而不是 "北京多云转晴 23~35度"呢?

眼尖的你一定发现问题了吧,其实是我在写代码的时候太着急了 忘记了ReleaseBuffer().....
为什么没有ReleaseBuffer就会出现这样的问题呢?我都已经进行了memcpy了呀?

下面就来详细探讨下GetBuffer 和 ReleaseBuffer 的原理吧~~~~


GetBuffer:

LPTSTR CString::GetBuffer(int nMinBufLength)
{
 ASSERT(nMinBufLength >= 0);

 if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
 {
  // we have to grow the buffer
  CStringData* pOldData = GetData();
  int nOldLen = GetData()->nDataLength;   // AllocBuffer will tromp it
  if (nMinBufLength < nOldLen)

  {
      nMinBufLength = nOldLen;

  }
  AllocBuffer(nMinBufLength);
  memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
  GetData()->nDataLength = nOldLen;
  CString::Release(pOldData);
 }
 ASSERT(GetData()->nRefs <= 1);

 // return a pointer to the character storage for this string
 ASSERT(m_pchData != NULL);
 return m_pchData;
}


参数:
指定:表示要重新申请的缓冲大小,重新申请的字符串的长度如果小于等于先前的字符串长度, 则不会重新分配内存使用原来的内存;如果大于当前字符串长度,则要重新分配缓冲,然后把旧缓冲给Release掉。
不指定:默认为0,表示缓冲大小为当前值,而且不会申请新的缓冲。

返回值:
指定并大于当前长度,返回的是新申请的缓冲的指针;
不指定或指定但小于当前长度,返回的是当前缓冲的指针。

可以基于GetBuffer返回的指针,对缓冲进行操作,从而修改CSting的内容。

 

由上可知,在确定对CString对象当前缓存的操作不会越界的前提下,不必指定GetBuffer的参数,之后对CString的操作都是在当前缓存上进行的;而如果可能造成越界,则必须指定一个值,此时,CString会在内部重新申请一块缓存,作为新的当前缓存。

 


ReleaseBuffer:

void CString::ReleaseBuffer(int nNewLength)
{
 CopyBeforeWrite();  // just in case GetBuffer was not called

 if (nNewLength == -1)
  nNewLength = lstrlen(m_pchData); // zero terminated

 ASSERT(nNewLength <= GetData()->nAllocLength);
 GetData()->nDataLength = nNewLength;
 m_pchData[nNewLength] = '\0';
}

 

ReleaseBuffer的作用只是负责消除多余的缓存内容,比如通过GetBuffer(100)申请了100个字符的空间,但后续只使用了其中的50个,则此时调用ReleaseBuffer()就会将未使用的50个空间释放掉。它并不是说释放掉通过GetBuffer分配的全部缓存空间(实际上,CString目前占用的空间在CString对象释放的时候才由CString对象自动负责释放)。

同时 ReleaseBuffer还有一个很重要的作用,就是“ GetData()->nDataLength = nNewLength;”
CString对象在内存中用一个计数器来维持可用缓冲区的大小
ReleaseBuffer的作用就是更新字符串的长度。 CString内,GetLength获取字符串长度并不是动态计算的,而是在赋值操作后计算并保存在一个int变量内的,当通过GetBuffer直接修改CString时,那个int变量并不可能自动更新,于是便有了ReleaseBuffer.


 

SO..

1)不管是用哪种GetBuffer获得的缓存,在CString对象销毁的时候,这些缓存都会自动销毁。
2)在GetBuffer和ReleaseBuffer之间,不要调用CString的成员函数。此时得到的结果,将是不准确、不可预知的,甚至会发生访问错误。

 

 

但使用时需要注意以下问题:

     如果要保存的内容不是以0结尾, 比如是读取文件数据, 则GetBuffer参数如果大于文件长度时, ReleaseBuffer参数一定要为文件长度(如果GetBuffer参数为文件长度的话不存在问题, ReleaseBuffer参数可以为默认-1)!

 

通过以上学习我明白啦~ 没有经过releaseBuffer的时候虽然我已经分配了内存拷贝了值,但是 WeatherZone 、WeatherInfo、Weatherglass 的长度都还是老样子 是0呢,所以做CString的+运算 得到的值就是“” 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值