GetBuffer()、LPCTSTR

CString::GetBuffer

LPTSTR GetBuffer( int nMinBufLength );

throw( CMemoryException );

//

这个函数是为一个CString对象重新获取其内部字符缓冲区的指针,返回的LPTSTR为非const,从而允许直接修改CString中的内容

如果nMinBufLength(最小占用长度) 比当前buffer长度大,那么就调用GetBuffer函数去释放当前的Buffer,用一个被请求的大小去覆盖这个buffer并且重新设定计数器为0,如果在这之前你在这个buffer中调用了LockBuffer,那么你将失去你当前锁定的buffer

//

如果你使用这个指向由GetBuffer所改变返回的字符串内容,那么在你使用CString其他CString方法之前你必须调用ReleaseBuffer

在调用ReleaseBuffer函数之后GetBuffer中的内容将无效(也就是销毁)

当这个CString被销毁的时候,这个buffer所占用的内存将被自动释放

注意这个如果你知道了这个字符串的长度,你不可以直接添加NULL字符了事,当你使用ReleaseBuffer的时候,无论如何,你必须指定最后的字符串的长度,如果你仅仅添加了一个NULL字符结束符给这个字符串,你应该给ReleaseBuffer传递一个-1, 当这个函数结束的时候,_tcslen 将决定这个buffer的长度

//

// example for CString::GetBuffer

CString s( "abcd" );//定义一个CString s并且初始化为abcd

#ifdef _DEBUG

afxDump << "CString s " << s << "\n";

#endif

LPTSTR p = s.GetBuffer( 10 );//定义一个指针指向LPTSTR并接受GetBuffer所返回的地址

lstrcpy( p, _T("Hello") ); // directly access CString buffer,使用lstrcpyHello复制到该buffer

s.ReleaseBuffer( );//释放buffer

#ifdef _DEBUG

afxDump << "CString s " << s << "\n";这时候s="Hello";

#endif

//

这是一个非常容易被用错的函数,主要可能是由于大家对它的功能不太了解。其实点破的话,也不是那么深奥。

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(); //千万不能缺少 [释放对应的指针psz?并把psz=nothing?封口-去掉多余的空间,并使返回的指针psz失效!]

fclose(fp);

}

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

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

 

LPTSTR lstrcpy(LPTSTR lpString1,LPCTSTR lpString2);

 

CStringT里面好像没有GetBuffer()成员函数?VS2010MFC中的CString还是有GetBuffer()成员函数的![ATL/MFC Concepts里面有Strings (ATL/MFC)--Using CString]

 

CStingGetBuffer()ReleaseBuffer()

GetBuffer和ReleaseBuffer是从其父类CSimpleStringT继承过来的。 GetBuffer的作用是:“Returns a pointer to the internal character buffer”,ReleaseBuffer的作用是:“Releases control of the buffer allocated by GetBuffer.”。这两个函数的常见用法如下:

CString str;

const int bufferSize = 10;

 

LPTSTR p str.GetBuffer(bufferSize);

_tcscpy_s(p, bufferSize, _T("abcd1234.")); // use the buffer directly

str.ReleaseBuffer(); // Surplus(多余的) memory released, p is now invalid.

给GetBuffer函数传递的参数bufferSize,意思是:“The minimum size of the character buffer in characters. This value does not include space for a null terminator.”。对于调用ReleaseBuffer释放内存时,是否应该带参数,msdn是这样说的:“If you keep track of the string length yourself, you should not append the terminating null character. You must, however, specify the final string length when you release the buffer with ReleaseBuffer. If you do append a terminating null character, you should pass –1 (the default) for the length to ReleaseBuffer, and ReleaseBuffer will perform a strlen on the buffer to determine its length.”。因为ReleaseBuffer函数的默认参数是-1,所以通常在调用ReleaseBuffer函数时省去-1参数的书写。

还有一点非常重要,看如下示例程序:

CString str;

const int bufferSize = 10;

 

LPTSTR p str.GetBuffer(bufferSize);

_tcscpy_s(p, bufferSize, _T("abcd")); // use the buffer directly

str.Append(_T("1234"));

str.ReleaseBuffer(); // Surplus(多余的) memory released, p is now invalid.

当程序执行完Append函数之后,程序员期望的是str字符串里保存的字符序列是abcd1234,但实际上并不是这样。有可能str的内容仍然为abcd,或者直接变为1234。这个问题在我之前的项目中曾经遇到过,最后才把问题定位到这里,来看msdn的注释:“If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before using any other CSimpleStringT member methods.”。也就是说如果程序中通过GetBuffer 函数返回的字符指针修改了字符串的内容,那么必须在使用任何其他的CString类成员函数之前先调用ReleaseBuffer。

 

GetBufferReleaseBuffer的用法,CString剖析

GetBuffer()主要作用是将字符串的缓冲区长度锁定,releaseBuffer则是解除锁定,使得CString对象在以后的代码中继续可以实现长度自适应增长的功能。

CString ::GetBuffer有两个重载版本:

LPTSTR GetBuffer( );LPTSTR GetBuffer(int nMinBufferLength);

在第二个版本中,当设定的长度小于原字符串长度时,nMinBufLength = nOldLen,该参数会被忽略,不分配内存,指向原CString;当设定的长度大于原字符串本身的长度时就要重新分配(reallocate)一块比较大的空间出来。而调用第一个版本时,应如通过传入0来调用第二个版本一样。

是否需要在GetBuffer后面调用ReleaseBuffer(),是根据你的后面的程序是否需要继续使用该字符串变量,并且是否动态改变其长度而定的。如果你GetBuffer以后程序自函数就退出,局部变量都不存在了,调用不调用ReleaseBuffer没什么意义了。

补充一下:

GetBuffer说白了就两个功能:

1:就是将CString里面的内存交到外部一个来处理,外部可以直接修改它的内容。

2:重新修改CString的内存大小,这个数值不包含null结尾符。

另一个典型的用法:就是将CString里面的内容变为int或long型,需要先获取里面的内存指针。这样就可以先GetBuffer(内存大小)方便直接转换。

如果在外部修改了CString里面的内容,在重新使用CString之前,需调用ReleaseBuffer()也就是说,ReleaseBuffer不需要每次都调用。

MSDN原文:

If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before using any other CSimpleStringT member methods.

The buffer memory is automatically freed when the CSimpleStringT object is destroyed.

If you keep track of the string length yourself, you should not append the terminating null character. You must, however, specify the final string length when you release the buffer with ReleaseBuffer. If you do append a terminating null character, you should pass –1 (the default) for the length to ReleaseBuffer, and ReleaseBuffer will perform a strlen on the buffer to determine its length.

CStringGetBuffer用法,GetBuffer本质,GetBuffer常见问题解决方法

一.函数原型

CString::GetBuffer

LPTSTR GetBuffer( int nMinBufLength );

throw( CMemoryException );

Return Value

An LPTSTRpointer to the objects (null-terminated) character buffer.

Parameters

nMinBufLength

The minimum size of the character buffer in characters. This value does not include space for a null terminator.

Remarks

Returns a pointer to the internal character buffer for the CString object. The returned LPTSTR is not const and thus allows direct modification of CString contents.

If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before using any other CString member functions. 

二.函数作用及使用范围

对一个CString变量,你可以使用的唯一合法转换符是LPCTSTR,直接转换成非常量指针(LPTSTR-[const] char*)是错误的。正确的得到一个指向缓冲区的非常量指针的方法是调用GetBuffer()方法。

GetBuffer()主要作用是将字符串的缓冲区长度锁定,releaseBuffer则是解除锁定,使得CString对象在以后的代码中继续可以实现长度自适应增长的功能。

CString ::GetBuffer有两个重载版本:

LPTSTR GetBuffer( );LPTSTR GetBuffer(int nMinBufferLength);

在第二个版本中,当设定的长度小于原字符串长度时,nMinBufLength = nOldLen,该参数会被忽略,不分配内存,指向原CString;当设定的长度大于原字符串本身的长度时就要重新分配(reallocate)一块比较大的空间出来。而调用第一个版本时,应如通过传入0来调用第二个版本一样。

是否需要在GetBufer后面调用ReleaseBuffer(),是根据你的后面的程序是否需要继续使用该字符串变量,并且是否动态改变其长度而定的。如果你GetBuffer以后程序自函数就退出,局部变量都不存在了,调用不调用ReleaseBuffer没什么意义了。

最典型的应用就是读取文件:

CFile file;

// FILE_NAME 为实现定义好的文件名称

if(file.Open(FILE_NAME,CFile::modeRead))

{

       CString szContent;

       int nFileLength = file.GetLength();

       file.Read(szContent.GetBuffer(nFileLength),nFileLength);

       szContent.ReleaseBuffer();

       // 取得文件內容放在szContent中,我们之后可以对其操作

}

三.测试

以下就CString::GetBuffer,做简单测试:

测试1:

// example for CString::GetBuffer

 

#include <stdio.h>

#include <afx.h>

 

void main(void)

{    

       CString s( "abcd" );

       printf("(1)before GetBuffer:\n");

       printf("CString s.length=%d\n",s.GetLength());

       printf("CString s=%s\n",s);

      

       LPTSTR p = s.GetBuffer( 2 );

      

       printf("(2)after GetBuffer and before ReleaseBuffer:\n");

       printf("LPTSTR p=%s\n",p);    

       printf("p.length=%d\n",strlen(p));

       printf("CString s=%s\n",s);      

       printf("CString s.length=%d\n",s.GetLength());

       s.ReleaseBuffer( );

       printf("(3)after ReleaseBuffer:\n");

       printf("LPTSTR p=%s\n",p);    

       printf("p.length=%d\n",strlen(p));

       printf("CString s=%s\n",s);

       printf("CString s.length=%d\n",s.GetLength());    

}

测试结果1:

(1)before GetBuffer:

CString s.length=4

CString s=abcd

(2)after GetBuffer and before ReleaseBuffer:

LPTSTR p=abcd

p.length=4

CString s=abcd

CString s.length=4

(3)after ReleaseBuffer:

LPTSTR p=abcd

p.length=4

CString s=abcd

CString s.length=4

Press any key to continue

测试2:

将LPTSTR p = s.GetBuffer( 2 ); 修改为:LPTSTR p = s.GetBuffer( 10 );

测试结果同1。

测试3:

在测试二的LPTSTR p = s.GetBuffer( 10 );后添加  p[5]='f';

测试结果同1。

测试4:

将测试三的p[5]='f';修改为p[4]='e';

测试结果4:

(1)before GetBuffer:

CString s.length=4

CString s=abcd

(2)after GetBuffer and before ReleaseBuffer:

LPTSTR p=abcde屯屯?

p.length=10

CString s=abcde屯屯?

CString s.length=4

(3)after ReleaseBuffer:

LPTSTR p=abcde屯屯?

p.length=10

CString s=abcde屯屯?

CString s.length=10

Press any key to continue

很显然(2)after GetBuffer and before ReleaseBuffer:中 CString s.length=4结果有问题。

注意:以上测试是在_MBCS环境下,如果换成_UNICODE则结果有可能不同。

 

 

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

if   (GetData()-> nRefs   >   1   ||   nMinBufLength   >   GetData()-> nAllocLength)
{
#ifdef   _DEBUG
//   give   a   warning   in   case   locked   string   becomes   unlocked
if   (GetData()   !=   _afxDataNil   &&   GetData()-> nRefs   <   0)
TRACE0( "Warning:   GetBuffer   on   locked   CString   creates   unlocked   CString!\n ");
#endif
//   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;
}

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 ';
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值