先 轉載一段別人的文章
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 參數如下圖所示:
////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 參數如下所示:
////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參數值如下所示:
////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();
對於一個CString 進行GetBuffer后,在進行該CString 的其他 CString 函數操作(尤其是 “=” “+” 等容易忽視的 CString 操作)前ReleaseBuffer(雖然從此處的幾段代碼執行情況來看,表面上在GetBuffer后在一次執行 CString操作不會導致錯誤,但是進行第二次CString 操作時就會產生錯誤。為了安全起見,getbuffer后需要在次執行CString的函數操作,先ReleaseBuffer()).