CString採用copy-on-write機制(可以實現多個對象共享一塊內存),高效而節省內存。
CString只有一個成員變量,長度爲4,即 sizeof(CString) == 4:
class CString
{
// functions ...
protected:
LPTSTR m_pchData; // pointer to ref counted string data
// functions ...
};
CString 使用結構體CStringData來管理數據:
struct CStringData
{
long nRefs; // reference count
int nDataLength; // length of data (including terminator)
int nAllocLength; // length of allocation
// TCHAR data[nAllocLength]
TCHAR* data() // TCHAR* to managed data
{ return (TCHAR*)(this+1); }
};
該結構體長度爲12,有三個變量:
1、nRefs,CString的引用個數;
2、nDataLength,爲字符串的長度,長度不算最後一個結束符'\0',也不包括CStringData結構體的長度12字節;
3、nAllocLength,爲字符串開闢緩存的長度,不包括CStringData結構體的長度12字節;
源碼說明一切:
nLen = strlen(...);
new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
nAllocLength = nLen;
而CString的成員變量m_pchData指針並不指向緩存的起始位置,而是指向該連續緩存的第13個字節處,恰巧就是字符串區域。
進一步,從CString的成員變量m_pchData向前偏移12個字節,恰巧就是CStringData結構體。這個結構體的nRefs爲copy-on-write機制提供了保障,nDataLength僅僅就是記錄字符串的長度,nAllocLength爲了管理短小字符串,提高效率,如下:
if (nLen <= 64)
{
pData = (CStringData*)_afxAlloc64.Alloc();
pData->nAllocLength = 64;
}
else if (nLen <= 128)
{
pData = (CStringData*)_afxAlloc128.Alloc();
pData->nAllocLength = 128;
}
else if (nLen <= 256)
{
pData = (CStringData*)_afxAlloc256.Alloc();
pData->nAllocLength = 256;
}
else if (nLen <= 512)
{
pData = (CStringData*)_afxAlloc512.Alloc();
pData->nAllocLength = 512;
}
GetBuffer函數遇到下面兩種情況之一時會創建一個新對象給調用者:
1、有大於1個的引用時(也就是有多個對象共享內存時);
2、GetBuffer傳遞的參數nMinBufLength大於原始原始分配長度時,刪除原來緩存,開闢更大的緩存。
GetBuffer返回一個字符串指針,可以像操作 TCHAR* 一樣操作,並立即反映到CString對象中。
ReleaseBuffer可以理解爲重新設置CString的字符串有效長度。(當然ReleaseBuffer也考慮到了多個對象共享的情況,它不會設置其共享對象的長度。最好不要在TCHAR* p = GetBuffer之後再引用該對象,此時p指向了所有共享對象的字符串內存。)
ReleaseBuffer做了兩個動作:
1、多個對象共享時,啓用copy-on-write機制,新建一個對象。
2、重新設置CString的有效長度。
所以,在調用GetBuffer之後,如果沒有共享,並且不需要重新設置有效長度(沒有更改字符),完全可以不調用ReleaseBuffer。
exemple:
CString str0 = "abcdefghijklmnopqrstuvwxyz";
CString str1 = str0;
char* p = str0.GetBuffer(0);
CString str2 = str0;
p[0] = '1';
p[1] = '2';
p[2] = '3';
p[3] = '4';
p[4] = '5';
str0.ReleaseBuffer(5);
執行完之後的結果:
str0 {"12345"}
str1 {"abcdefghijklmnopqrstuvwxyz"}
str2 {"12345fghijklmnopqrstuvwxyz"}