深入解析CString的内存结构
更新时间:2023-10-08 01:16:01 阅读量: 综合文库 文档下载
- 深入解析windows推荐度:
- 相关推荐
深入解析MFC -- CString的内存结构
VC6的时候记得看过CString的源代码,并不复杂,应该是从VC7开始,MFC和ATL共用一个CString了,新的CString使用了模板技术和其它技术,值得一提。 先 看CString的定义: typedef CAtlString CString;
如果想明确使用ANSI和UNICODE版本,可以使用CStringA和CStringW,看它们的定义:
typedef CAtlStringW CStringW; typedef CAtlStringA CStringA;
以上三个Atl版本的String,其定义为:
typedef CStringT< wchar_t, StrTraitATL< wchar_t > > CAtlStringW; typedef CStringT< char, StrTraitATL< char > > CAtlStringA; typedef CStringT< TCHAR, StrTraitATL< TCHAR > > CAtlString; 因此,CStringT才是真实的CString类。
template< typename BaseType, class StringTraits > class CStringT :
public CSimpleStringT< BaseType,
_CSTRING_IMPL_::_MFCDLLTraitsCheck
CStringT有两个模板参数,第一个表明字符类型,第二个参数从源代码中知道是StrTraitATL:
template< typename _BaseType = char, class StringIterator = ChTraitsOS< _BaseType > >
class StrTraitATL : public StringIterator {
public:
static HINSTANCE FindStringResourceInstance(__in UINT nID) throw() {
return( AtlFindStringResourceInstance( nID ) ); }
static IAtlStringMgr* GetDefaultManager() throw() {
return( &g_strmgr ); } };
从类声明看到他提供了一个字符串管理器,字符迭代器和从资源中获得字符串的功能。字符串管理器比较重要,后面会提到。
CStringT没有成员变量,封装了很多好用的字符串函数,数据在基类CSimpleStringT中。
CSimpleStringT只有一个成员变量m_pszData,不要小看这个变量,在它身上,有着很多秘密,绝对不是他的声明那么朴实: PXSTR m_pszData;
PXSTR就是char或者wchar_t,只不过被模板的特化技术封装了一下。
CSimpleStringT没有直接操作m_pszData,而是通过成员函数GetData来获得,看一下这个函数:
CStringData* GetData() const throw() {
return( reinterpret_cast< CStringData* >( m_pszData )-1 ); }
这 个函数将m_pszData指向的内存转成CStringData类型,然后往前移动sizeof(CStringData)的长度,指向了一个 CStringData对象。m_pszData的秘密就在此处,实际上,每次分配内存时,都会多分配一段sizeof(CStringData)长度的 内存,最前面这段数据格式化为CStringData对象,然后m_pszData指向其后的数据,这才是字符串。
|_______________|___________________________________________________| CStringData m_pszData 再看CStringData的声明: struct CStringData {
IAtlStringMgr* pStringMgr; // String manager for this CStringData int nDataLength; // Length of currently used data in XCHARs (not including terminating null)
int nAllocLength; // Length of allocated data in XCHARs (not including terminating null)
long nRefs; // Reference count: negative == locked
// XCHAR data[nAllocLength+1] // A CStringData is always followed in memory by the actual array of character data };
CStringData包含了这个字符串的所有信息,包括字符串长度,内存长度和引用计数,另外还有一个字符串管理器指针,这个指针从前面所提到的模板参数StrTraitATL中得到。再看看接口IAtlStringMgr的声明: __interface IAtlStringMgr {
public:
// Allocate a new CStringData
CStringData* Allocate( int nAllocLength, int nCharSize ) throw(); // Free an existing CStringData
void Free( CStringData* pData ) throw();
// Change the size of an existing CStringData
CStringData* Reallocate( CStringData* pData, int nAllocLength, int nCharSize ) throw();
// Get the CStringData for a Nil string CStringData* GetNilString() throw();
IAtlStringMgr* Clone() throw(); };
IAtlStringMgr提供了字符串内存的分配和销毁。具体实现参考类CAfxStringMgr。
我们还是先看看一个字符串是如何赋值的吧,给下面第二行代码加上断点,调试进入:
CString s;
s = L\
一直跟踪到wmemcpy_s函数,才找到了拷贝的函数,以下是堆栈: s = L\
CStringT::operator=() // a CSimpleStringT::operator=() // b SetString(const wchar_t * pszSrc) // c SetString(const wchar_t * pszSrc, int nLength) // d CopyChars // e 一行行来分析:
a,调用基类CSimpleStringT的操作符= b,调用SetString
c,求字符串pszSrc长度,调用两个参数的SetString
d,调用GetBuffer分配内存空间,然后判断新字符串是否与现有字符串重叠,重叠调用CopyCharsOverlapped拷贝新字符串,不重叠调用CopyChars e,CopyChars就是wmemcpy_s
在上面的步骤中,值得关注的GetBuffer函数。我们继续进入这个函数看看发生了什么: SetString
GetBuffer // a PrepareWrite // b PrepareWrite2 // c Fork // d CAfxStringMgr::Allocate // e _malloc_dbg // f a,调用PrepareWrite
b,判断引用计数是否大于1或者长度不够,满足任意一个条件,都需要调用PrepareWrite重新分配内存,否则直接返回m_pszData
c,首先判断新申请的长度是否小于已经内存长度,如果小于,则将长度设置为已有内存长度。然后判断引用计数是否大于1,是则调用Fork重新申请内存。如果引用计数不大于1,则看是否需要申请内存,是则重新分配。重新分配有一个简单的原则,以下这段比较清楚:
if( pOldData->nAllocLength < nLength ) {
// Grow exponentially, until we hit 1K. int nNewLength = pOldData->nAllocLength; if( nNewLength > 1024 )
{
nNewLength += 1024; } else {
nNewLength *= 2; }
if( nNewLength < nLength ) {
nNewLength = nLength; }
Reallocate( nNewLength ); }
d,取出旧的CStringData,克隆一个IAtlStringMgr,并分配nLength长度的内存。格式化新分配的内存,并释放旧内存。注意释放的方式,并不是直接free内存,而是调用了CStringData的Release: void Release() throw() {
ATLASSERT( nRefs != 0 );
if( _AtlInterlockedDecrement( &nRefs ) <= 0 ) {
pStringMgr->Free( this ); } }
可以看到只有引用计数小于或等于0了,才会直接free内存。 e,具体看代码吧:
CStringData* CAfxStringMgr::Allocate( int nChars, int nCharSize ) throw() {
size_t nTotalSize; CStringData* pData; size_t nDataBytes;
nDataBytes = (nChars+1)*nCharSize;
nTotalSize = sizeof( CStringData )+nDataBytes; pData = (CStringData*)malloc( nTotalSize ); if (pData == NULL) return NULL;
pData->pStringMgr = this; pData->nRefs = 1;
pData->nAllocLength = nChars; pData->nDataLength = 0; return pData; }
可以看到实际分配的内存大小是字符串长度+1个NULL+sizeof(CStringData) f,分配内存
正在阅读:
深入解析CString的内存结构10-08
四个意识个人自查自纠对照检查材料(存在的问题清单及整改措施)范文好03-12
【化学】2018中考化学真题分类汇总及解析——综合计算题(一)05-30
体育与健康理论试题之109个名词解释11-01
1项目前期策划合同的要点03-11
K12学习语文S版六年级语文下册第二单元教案(二)03-06
三年级口算试题100道03-25
国家级大学生创新创业训练项目03-16
2020计算机培训心得体会5篇整理03-20
英语中那些你不知道的冷知识03-16
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 解析
- 深入
- 内存
- CString
- 结构
- 21世纪大学新英语读写译第一册A,B
- 不受版面费的期刊
- MATLAB在电路中的应用
- 200个岗位职责大全
- 《画家和牧童》第二课时
- 天津市静海县第一中学2019届高三语文12月学生学业能力调研试题
- 速达V3-PRO 软件练习题-初始化帐套
- 机车综合无线通信设备(CIR)教材部分
- 团队干部网上培训试卷
- 采购部工作总结报告
- 2016-2022年中国医用可吸收缝合线行业发展现状及十三五投资前景评估报告
- 公开课课堂教学评价表 - 图文
- 大学物理下学期练习6--8答案
- 2016-2022年中国医疗器械电商行业现状深度调研及十三五产业投资评估报告
- 危化试题,安全管理
- 我看《儒林外史》中严监生这一形象概述
- 精品材料力学试卷三套含答案分解
- 辽宁省部分重点中学协作体2018届高三4月模拟考试英语
- 2018年下半年班级工作总结
- 在人民政府公众网站开通仪式上的讲话