您当前位置:地名问答 > 中国 > 浙江 > 杭州 > 西湖区 > 断桥残雪 > 断桥残雪地名
CString需要注意的地方(2)
更新:2017-08-18 01:51【断桥残雪地名】
导读:其中前面 sizeof(CstringData) 个 BYTE 是用来存放 CstringData 信息的。后面的 nLen + 1 个 TCHAR 才是真正用来存放字符串的,多出来的一个用来存放 /0 。 Cstring 中所
其中前面sizeof(CstringData) 个BYTE 是用来存放CstringData 信息的。后面的nLen +1 个TCHAR 才是真正用来存放字符串的,多出来的一个用来存放’/0’ 。
Cstring 中所有的operations 的都是针对这个缓冲区的。比如LPTSTR CString::GetBuffer(int nMinBufLength) ,它的实现方法是:
首先通过Cstring::GetData() 取得CstringData 对象的指针。该指针是通过存放字符串的指针m_pchData 先后偏移sizeof(CstringData) ,从而得到了CstringData 的地址。然后根据参数nMinBufLength 给定的值重新实例化一个CstringData 对象,使得新的对象里的字符串缓冲长度能够满足nMinBufLength 。
然后在重新设置一下新的CstringData 中的一些描述值。最后将新CstringData 对象里的字符串缓冲直接返回给调用者。
这些过程用C++ 代码描述就是:
if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
{
// 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;
很多时候,我们经常的对大批量的字符串进行互相拷贝修改等,Cstring 使用了CopyBeforeWrite 技术。使用这种方法,当利用一个Cstring 对象a 实例化另一个对象b 的时候,其实两个对象的数值是完全相同的,但是如果简单的给两个对象都申请内存的话,对于只有几个、几十个字节的字符串还没有什么,如果是一个几K 甚至几M 的数据量来说,是一个很大的浪费。
因此Cstring 在这个时候只是简单的将新对象b 的字符串地址m_pchData 直接指向另一个对象a 的字符串地址m_pchData 。所做的额外工作是将对象a 的内存应用CstringData:: nRefs 加一。
CString::CString(const CString& stringSrc)
{
m_pchData = stringSrc.m_pchData;
InterlockedIncrement(&GetData()->nRefs);
}
这样当修改对象a 或对象b 的字符串内容时,首先检查CstringData:: nRefs 的值,如果大于一( 等于一,说明只有自己一个应用该内存空间) ,说明该对象引用了别的对象内存或者自己的内存被别人应用,该对象首先将该应用值减一,然后将该内存交给其他的对象管理,自己重新申请一块内存,并将原来内存的内容拷贝过来。
其实现的简单代码是:
void CString::CopyBeforeWrite()
{
if (GetData()->nRefs > 1)
{
CStringData* pData = GetData();
Release();
AllocBuffer(pData->nDataLength);
memcpy(m_pchData, pData->data(),
(pData- >nDataLength+1)*sizeof(TCHAR));
}
}
其中Release 就是用来判断该内存的被引用情况的。
void CString::Release()
{
if (GetData() != _afxDataNil)
{
if (InterlockedDecrement(&GetData()->nRefs) <= 0)
FreeData(GetData());
}
}
很赞哦! (82)