日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CString对象的一种错误的使用方式

發布時間:2025/3/21 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CString对象的一种错误的使用方式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
我現在做的系統有的時候會出現這樣的斷言失敗: Debug Error! DAMAGE: after Normal block (#328Array) at 0x182C30F0. 跟蹤一下,發現問題竟出在CString的析構函數中,于是拿出了大半天的時間來研究這個問題,終于發現了原因所在。 問題的起因是我像下面這樣調用無參的構造函數聲明一個CString對象: CString strText; 然后把它以這樣的方式傳遞給別的函數:(函數1) pVCG->GetRotDirection(WAVE_P, m_nWaveSide, strText.GetBuffer(0)); 而在這個函數里對于字符串指針進行了類似于如下的操作: sprintf(strDir, "%s", "CW"); 這樣做的危險性在于當字符串沒有被初始化的時候,CString內部指向緩沖區的指針指向的是一個隨機的地址,在CString的無參構造函數調用 了如下函數: _AFX_INLINE void CString::Init() { m_pchData = afxEmptyString.m_pchData; } m_pdhData的定義:LPTSTR m_pchData; afxEmptyString的定義是: #define afxEmptyString AfxGetEmptyString() const CString& AFXAPI AfxGetEmptyString() { return *(CString*)&_afxPchNil; } _afxPchNil的來源如下: AFX_STATIC_DATA int _afxInitData[] = { -1, 0, 0, 0 }; AFX_STATIC_DATA CStringData* _afxDataNil = (CStringData*)&_afxInitData; AFX_COMDAT LPCTSTR _afxPchNil = (LPCTSTR)(((BYTE*)&_afxInitData)+sizeof(CStringData)); 從上面的代碼可以看出,沒有進行初始化操的CString對象它們的緩沖區指針都是指向一塊相同的內存:和一個全局數組相關的地址。 而在函數1例調用sprintf修改CString對象的緩沖區的結果是修改所有未初始化CString內部緩沖區指針所指,這么做是非常危險的。但是這還不是出現斷言錯誤的原因。 接下來的錯誤,更難被發現。接著我的程序又調用了兩次類似于下面的函數(函數2) pVCG->GetCompressionGrade(WAVE_QRS, m_nWaveSide, 0, 60, 0, 0, strText); 在這個函數的內部有str.Format(IDS_COMPRESSION_LESS);這樣的操作。 這是MFC里CString::Format的相關代碼: void AFX_CDECL CString::Format(UINT nFormatID, ...) { CString strFormat;//沒有直接修改自己,而是先對新聲明的字符串進行操作 VERIFY(strFormat.LoadString(nFormatID) != 0); ? va_list argList; va_start(argList, nFormatID); FormatV(strFormat, argList); va_end(argList); } 而在void CString::FormatV(LPCTSTR lpszFormat, va_list argList)里最后作如下操作: GetBuffer(nMaxLen); VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());//將修改后的字符串拷貝到自己的緩沖區內 ReleaseBuffer(); 關鍵在GetBuffer: 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; } 由于字符串沒有被初始化,所以GetData()->nAllocLength=0,因此if語句塊被執行,重新在堆上分配內存,銷毀原來的內存,這才第一次給字 符串分配內存。 這時還不會出現問題,接下來還會執行類似函數1的操作。 最后問題之所以發生在CString被析構的時候,原因就在于,在執行函數2的時候,字符串有了能容納4個字節的緩沖區.如果調試的時候打開Memory窗口,在Address:文本框里輸入一個堆內存的地址,可以發現VC在調試版的程序里為每個在堆里分配的內存塊的后面加了4個字節的內容,值全為FD,用于檢查內存越界。CString析構的時候,調用了調試版的operator delete,它就以此為依據進行了內存檢測: if (!CheckBytes(pbData(pHead) + pHead->nDataSize, _bNoMansLandFill, nNoMansLandSize)) _RPT3(_CRT_ERROR, "DAMAGE: after %hs block (#%d) at 0x%08X.\n", ??????????????????? szBlockUseName[_BLOCK_TYPE(pHead->nBlockUse)], ??????????????????? pHead->lRequest, ??????????????????? (BYTE *) pbData(pHead)); 由于后來再次調用的函數1時它產生的長度有的時候會大于4 ,就破壞了后面的邊界,所以會出現這樣的問題。 出現這種問題時,在調試狀態下會在輸出窗口輸出如下類似信息: memory check error at 0x182C7F22 = 0x57, should be 0xFD 結論: 1.所以str.GetBuffer(0)作為參數傳遞的時候適合于作為只讀的參數; 2.如果非得要做可以修改的參數,那就得給GetBuffer傳遞一個保證足夠安全的參數,也就是足夠大; 2.如果調試版的程序出現類似 Debug Error! DAMAGE: after Normal block (#328Array) at 0x182C30F0. 的錯誤,應想到內存沖突。 問題終于水落石出了。反思一下,這個問題一點也不難,都怪自己基礎沒有打好,考慮問題不周全。

總結

以上是生活随笔為你收集整理的CString对象的一种错误的使用方式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。