Chinaunix首页 | 论坛 | 博客
  • 博客访问: 59040
  • 博文数量: 20
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 200
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-30 11:11
文章分类

全部博文(20)

文章存档

2018年(2)

2010年(2)

2009年(16)

我的朋友

分类:

2010-03-10 22:15:38

from %B6%AC%D2%E2%BE%D3/blog/item/a49173f93855ab50242df24d.html
这是一个非常容易被用错的函数,主要可能是由于大家对它的功能不太了解。其实点破的话,也不是那么深奥。
    这个函数是为一个CString对象重新获取其内部字符缓冲区的指针,返回的LPTSTR为非const的,从而允许直接修改CString中的内容! 如果nMinBufLength 比当前buffer大,那么将调用ReleaseBuffer函数去释放当前的Buffer,用一个被请求的大小去覆盖这个buffer。

  GetBuffer(int size)是用来返回一个你所指定大小可写内存的成员方法。它和被重载的操作符LPCTSTR还是有点本质区别的,LPCTSTR是直接返回一个只读内存 的指针,而GetBuffer则是返回一个可以供调用者写入的内存,并且,你可以给定大小。下面是个简单的,但也是非常典型的例子:

  int readFile(CString& str, const CString& strPathName)
  {
  FILE* fp = fopen(strPathName, "r"); // 打开文件
  fseek(fp, 0, SEEK_END);
  int nLen = ftell(fp); // 获得文件长度
  fseek(fp, 0, SEEK_SET); // 重置读指针
  char* psz = str.GetBuffer(nLen);
  fread(psz, sizeof(char), nLen, fp); //读文件内容
  str.ReleaseBuffer(); //千万不能缺少
  fclose(fp);
  }

  上面的函数是GetBuffer函数最典型的用法了,其实它就相当于申请一块nLen大小的内存,只不过,这块内存是被引用在CString对象的内 部而已,这是非常有效的一种用法,如果不直接用GetBuffer函数来申请的话,那么你必须用new操作符(或者malloc()函数)在 CString的外部申请,然后再将申请的内存拷贝到CString对象中,显然这是一个非常冗余的操作,会使你函数的效率大大下降。

  ReleaseBuffer函数是用来告诉CString对象,你的GetBuffer所引用 的内存已经使用完毕,现在必须对它进行封口,否则CString将不会知道它现在所包含的字符串的长度,所以在使用完GetBuffer之后,必须立即调 用ReleaseBuffer函数重置CString的内部属性,其实也就是头部信息。


    GetBuffer 的第一种用法,也是最简单的一种,不用给它传递参数,它使用默认值 0,意思是:“给我这个字符串的指针,我保证不加长它”。当你调用 ReleaseBuffer 时,字符串的实际长度会被重新计算,然后存入 CString 对象中。
    必须强调一点,在 GetBuffer 和 ReleaseBuffer 之间这个范围,一定不能使用你要操作的这个缓冲的 CString 对象的任何方法。因为 ReleaseBuffer 被调用之前,该 CString 对象的完整性得不到保障。

    假设你想增加字符串的长度,你首先要知道这个字符串可能会有多长,好比是声明字符串数组的时候用:char buffer[1024]; 表示 1024 个字符空间足以让你做任何想做得事情。
    在 CString 中与之意义相等的表示法:LPTSTR p = s.GetBuffer(1024); 调用这个函数后,你不仅获得了字符串缓冲区的指针,而且同时还获得了长度至少为 1024 个字符的空间(注意,我说的是“字符”,而不是“字节”,因为 CString 是以隐含方式感知 Unicode 的)。


    另外一个常见的错误是:既然固定大小的内存不工作,那么就采用动态分配字节,这种做法弊端更大:
int len = lstrlen(parm1) + 13 lstrlen(parm2) + 10 + 100;
char * buffer = new char[len];
sprintf(buffer, \"%s is equal to %s, valid data\", parm1, parm2);
CString s = buffer;
......
delete [] buffer;

    需要注意 sprintf 例子都不是 Unicode 就绪的,尽管你可以使用 tsprintf 以及用 _T() 来包围格式化字符串,但是基本 思路仍然是在走弯路,这这样很容易出错。
它可以能被简单地写成:
CString s;
s.Format(_T(\"%s is equal to %s, valid data\"), parm1, parm2);

阅读(725) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~