精解CString類的GetBuffer,ReleaseBuffer 函數(VC++)

CString的GetBuffer用法

一.函數原型

CString::GetBuffer

LPTSTR GetBuffer( int nMinBufLength );

throw( CMemoryException );

Return Value

An LPTSTR pointer to the object’s (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 notconst and thus allows direct modification of CString contents.

If you use the pointer returned by GetBuffer to change the string contents, you must callReleaseBuffer 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則結果有可能不同。

參考:

《CString GetBuffer()》

http://blog.csdn.net/hbyh/archive/2007/09/15/1786574.aspx

CStringGetBuffer問題

http://game.tongji.net/thread-379834-1-1.html

《CString的GetBuffer》

http://www.programfan.com/blog/article.asp?id=40755

《CString GetBuffer() and ReleaseBuffer()》

http://blog.csdn.net/guanchanghui/archive/2006/09/13/1217096.aspx

CString::GetBuffer()與CString::ReleaseBuffer到底有什麼用?

http://topic.csdn.net/t/20060313/22/4612156.html


====================================================================================================================

轉載:http://blog.pfan.cn/xman/43212.html

GetBuffer()主要作用是將字符串的緩衝區長度鎖定,releaseBuffer則是解除鎖定,使得CString對象在以後的代碼中繼續可以實現長度自適應增長的功能。

CString ::GetBuffer有兩個重載版本:

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

在第二個版本中,當設定的長度小於原字符串長度時,nMinBufLength = nOldLen,該參數會被忽

略,不分配內存,指向原CString;當設定的長度大於原字符串本身的長度時就要重新分配(reallocate)一塊比較大的空間出來。而調用第一個版本時,應如通過傳入0來調用第二個版本一樣。

是否需要在GetBufer後面調用ReleaseBuffer(),是根據你的後面的程序是否需要繼續使用該字符串變量,並且是否動態改變其長度而定的。如果你GetBuffer以後程序自函數就退出,局部變量都不存在了,調用不調用ReleaseBuffer沒什麼意義了。

這是一個非常容易被用錯的函數,主要可能是由於大家對它的功能不太瞭解。其實點破的話,也不是那麼深奧。
    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說白了就兩個功能:

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 CSimpleStringTmember 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 toReleaseBuffer, and ReleaseBuffer will perform a strlen on the buffer to determine its length.


=========================================================================================================================

CString str = "abcde\0cde";
輸出字符串的值爲: abcde

而字符串的長度爲 s.GetLength() 的值爲: 5

這是因爲CString對象在賦值時只檢查到'\0',後面的忽略了, 也就是說實際對象str內容爲"abcde".

而str真正的存儲空間爲6(字符串以'\0'結尾).

所以說在字符長度和實際的空間是不一樣的. 好!別跑!

請看下面有趣的程序:

CString str = "hello";

LPSTR pf = (LPSTR)(LPCSTR)s;

LPSTR pa = s.GetBuffer(0);

        你可以測得 pf == pa;

LPSTR pb = s.GetBuffer(10);

        你可以測得 pf != pb;

   

爲什麼:

我們都知道(LPSTR)(LPCSTR)s 實際指向對象str的實際字符串的內存地址, GetBuffer() 函數中的參數(其實就是重新申請的字符串的長度)如果小於等於先前的字符串長度, 則不會重新分配內存使用原來的內存所以 pf == pa, 如果大於先前的字符串長度, 則重新追加內存(也就是要複製原來的內容),

所以pf != pb.

   

注意GetBuffer()函數中的參數爲重新申請的字符串的長度, 實際內存的大小應再加1.

  

CString s = "hello";

LPSTR pf = s.GetBuffer(0);

strcpy(pf,"hi");

這時對象str 的內容爲 "hi"

但是s.GetLength()的值爲5, 如果加上一條語句:

s.ReleaseBuffer();

則s.GetLength()的值爲2

解釋: 
CString對象在內存中用一個計數器來維持可用緩衝區的大小

void ReleaseBuffer( int nNewLength = -1 )
     {
          if( nNewLength == -1 )
          {
               nNewLength = StringLength( m_pszData );
          }
          SetLength( nNewLength );
     }

很明顯ReleaseBuffer的作用就是更新字符串的長度。 CString內,GetLength獲取字符串長度並不是動態計算的,而是在賦值操作後計算並保存在一個int變量內的,當通過GetBuffer直接修改CString時,那個int變量並不可能自動更新,於是便有了ReleaseBuffer.

  

CString s = "hello";

LPSTR pf = s.GetBuffer(0);

strcpy(pf,"hi");

LPSTR ps =  (LPSTR)(LPCSTR)s;    字符串緩衝區的首地址

*(ps+2) = 'x';

  則字符串的實際內容爲:    "hixlo"

*(ps+6) = 'a';        出錯, 因爲對象s的實際空間爲 6

  

CString s = "hello";

LPSTR pf = s.GetBuffer(10);

strcpy(pf,"hi");

LPSTR ps =  (LPSTR)(LPCSTR)s;    字符串緩衝區的首地址

*(ps+2) = 'x';

*(ps+5)= '\0';

 則字符串的實際內容還是爲:    "hixlo"

*(ps+6) = 'a';         可以因爲s對象的實際空間爲11

  

說白了  ReleaseBuffer就是更新賦值之後的字符串的長度, 而實際空間沒有根本的變化, GetBuffer纔是使內存空間大小變化的罪魁禍首.

轉載:http://blog.sciencenet.cn/blog-481152-427173.html

發佈了7 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章