對於GetBuffer() 與 ReleaseBuffer() 的一些分析


先 轉載一段別人的文章

CString類的這幾個函數, 一直在用, 但總感覺理解的不夠透徹, 不時還有用錯的現象. 今天抽時間和Nico一起分析了一下, 算是撥開了雲霧:
GetBuffer和ReleaseBuffer是一套需要配合使用的函數, 與GetBufferSetLength相比, 優點是如果分配的空間大於實際保存的字符串(0結尾), ReleaseBuffer會把多余申請的空間釋放, 歸還給系統; 但使用時需要注意以下問題: 如果要保存的字符串為abc(0結尾), 則GetBuffer參數應至少為3; 如果要保存的內容不是以0結尾, 比如是讀取文件數據, 則GetBuffer參數如果大於文件長度時, ReleaseBuffer參數一定要為文件長度(如果GetBuffer參數為文件長度的話不存在問題, ReleaseBuffer參數可以為默認-1)!
CString csStr;

LPTSTR lpsz = csStr.GetBuffer(100);

lpsz[0] = 'a';

lpsz[1] = 'b';

lpsz[2] = '/0';

csStr.ReleaseBuffer();

int nLength = csStr.GetLength();

/* n的值為2 */

GetBufferSetLength相對比較容易理解, 它申請一個指定長度的空間, 即使里面最終保存的字符串長度小於申請的空間長度, 也不會將多余空間釋放.
CString csStr;

LPTSTR lpsz = csStr.GetBufferSetLength(100);

lpsz[0] = 'a';

lpsz[1] = 'b';

lpsz[2] = '/0';

int nLength = csStr.GetLength();

/* n的值還是為100 */

對於紅色部分,自己寫代碼時的確遇到過這樣的問題:代碼如下

  CString temp;
  ULONGLONG dwcount = Input_File.GetLength();
  //UINT dwcount = (UINT)Input_File.GetLength();
  Input_File.Read(temp.GetBuffer(dwcount),dwcount);
  temp.ReleaseBuffer(dwcount);

若temp.ReleaseBuffer()不指定參數,執行這一步是會遇到錯誤,所以,類似的文件讀取操作,releasebuffer的時候還是指定一個與getbuffer一樣的參數為好

另:對於

(如果GetBuffer參數為文件長度的話不存在問題, ReleaseBuffer參數可以為默認-1)!

我設置temp.ReleaseBuffer(-1);此句執行的時候仍然出現錯誤,故還是指定文件長度為好

 

接下來看看其他的代碼

CString str;
BROWSEINFO bi;
TCHAR name[MAX_PATH];
ZeroMemory(&bi,sizeof(BROWSEINFO));
bi.hwndOwner = GetSafeHwnd();
bi.pszDisplayName = name;
bi.lpszTitle = _T("選擇文件夾");
bi.ulFlags = BIF_RETURNFSANCESTORS;
LPITEMIDLIST idl = SHBrowseForFolder(&bi);
if(idl == NULL)
  return;


SHGetPathFromIDList(idl, str.GetBuffer(MAX_PATH));

////1
//CString aa = str.GetBuffer(MAX_PATH);
//CString bb = str;                         //運行此句之后,str內容變成亂碼

//int a = aa.GetLength();
//int b = str.GetLength();
//LPTSTR cc = str.GetBuffer(MAX_PATH);
//LPTSTR dd = bb.GetBuffer(MAX_PATH);
//cc[1] = 'a';

//bb.ReleaseBuffer();

debug 參數如下圖所示:

11

 

////2  
CString aa = str.GetBuffer(MAX_PATH);
int a = aa.GetLength();
int b = str.GetLength();                       //b無法獲取str的長度

LPTSTR cc = str.GetBuffer(MAX_PATH);
cc[1] = 'a';
int e = str.GetLength();
                       //e無法正確獲取str的長度,與3不同之處在於此處的str在藍色字體getbuffer后未releasebuffer                                                              //妥善的做法是在兩次str.getbuffer與str.GetLength()之間都都releasebuffer()下。
str.ReleaseBuffer();  
int d = str.GetLength();

debug 參數如下所示:

22

////3
//CString aa = str.GetBuffer(MAX_PATH);
//str.ReleaseBuffer();
//CString bb = str;                                  //bb的內容正確
//int a = aa.GetLength();
//int b = str.GetLength();

//LPTSTR cc = str.GetBuffer(MAX_PATH);
//LPTSTR dd = bb.GetBuffer(MAX_PATH);
//cc[1] = 'a';
//int d = str.GetLength();                     //此處雖然可以正確獲取str的值,但是在GetBuffer()后,最好還是在cc[1] = ‘a’ 后releasebuffer()一次。

                                                           //為何不再cc[1] = ‘a’前releasebuffer的原因: 雖然此處str仍然會變成”Ca/…..”,但是根據MSDN:在調用ReleaseBuffer之后,由GetBuffer返回的地址也許就無效了,因為其它的CString操作可能會導致CString緩沖區被重新分配。如果你沒有改變此CString的長度,則緩沖區不會被重新分配。 妥當的做法是在cc[1]后releasebuffer

debug參數值如下所示:

33

////4

str.ReleaseBuffer();                                  //  對上面的SHGetPathFromIDList(idl, str.GetBuffer(MAX_PATH));  進行的釋放操作
CString aa = str.GetBuffer(MAX_PATH);
CString bb = str;                                     // 執行完此句后,str的值不會變成亂碼,和1類比
int f = str.GetLength();                            //和1比,此處可以正確獲取長度

str.ReleaseBuffer(); 
int a = aa.GetLength();
int b = str.GetLength();
CString ff = str.GetBuffer(MAX_PATH);
LPTSTR dd = bb.GetBuffer(MAX_PATH);
int d = str.GetLength();            

image

 

 

 

對於一個CString 進行GetBuffer后,在進行該CString 的其他 CString 函數操作(尤其是 “=” “+” 等容易忽視的 CString 操作)前ReleaseBuffer(雖然從此處的幾段代碼執行情況來看,表面上在GetBuffer后在一次執行 CString操作不會導致錯誤,但是進行第二次CString 操作時就會產生錯誤。為了安全起見,getbuffer后需要在次執行CString的函數操作,先ReleaseBuffer()).


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM