您当前位置:地名问答 > 中国 > 浙江 > 杭州 > 西湖区 > 断桥残雪 > 断桥残雪地名
CString需要注意的地方
更新:2017-08-18 01:51【断桥残雪地名】
导读:很多的程序 , 发现很大的一部分 bug 是关于 MFC 类中的 Cstring 的错误用法的 . 出现这种错误的原因主要是对 Cstring 的实现机制不是太了解。 Cstring 是对于原来标准 c 中字符串类型的一种
很多的程序, 发现很大的一部分bug 是关于MFC 类中的Cstring 的错误用法的. 出现这种错误的原因主要是对Cstring 的实现机制不是太了解。
Cstring 是对于原来标准c 中字符串类型的一种的包装。因为,通过很长时间的编程,我们发现, 很多程序的bug 多和字符串有关, 典型的有:缓冲溢出、内存泄漏等。而且这些bug 都是致命的,会造成系统的瘫痪。因此c++ 里就专门的做了一个类用来维护字符串指针。标准c++ 里的字符串类是string ,在microsoft MFC 类库中使用的是Cstring 类。通过字符串类,可以大大的避免c 中的关于字符串指针的那些问题。
这里我们简单的看看Microsoft MFC 中的Cstring 是如何实现的。当然,要看原理,直接把它的代码拿过来分析是最好的。MFC 里的关于Cstring 的类的实现大部分在strcore.cpp 中。
Cstring 就是对一个用来存放字符串的缓冲区和对施加于这个字符串的操作封装。也就是说,Cstring 里需要有一个用来存放字符串的缓冲区,并且有一个指针指向该缓冲区,该指针就是LPTSTR m_pchData 。但是有些字符串操作会增建或减少字符串的长度,因此为了减少频繁的申请内存或者释放内存,Cstring 会先申请一个大的内存块用来存放字符串。这样,以后当字符串长度增长时,如果增加的总长度不超过预先申请的内存块的长度,就不用再申请内存。当增加后的字符串长度超过预先申请的内存时,Cstring 先释放原先的内存,然后再重新申请一个更大的内存块。同样的,当字符串长度减少时,也不释放多出来的内存空间。而是等到积累到一定程度时,才一次胜将多余的内存释放。
还有,当使用一个Cstring 对象a 来初始化另一个Cstring 对象b 时,为了节省空间,新对象b 并不分配空间,它所要做的只是将自己的指针指向对象a 的那块内存空间,只有当需要修改对象a 或者b 中的字符串时,才会为新对象b 申请内存空间,这叫做写入复制技术(CopyBeforeWrite) 。
这样,仅仅通过一个指针就不能完整的描述这块内存的具体情况,需要更多的信息来描述。
首先,需要有一个变量来描述当前内存块的总的大小。其次,需要一个变量来描述当前内存块已经使用的情况。也就是当前字符串的长度。另外,还需要一个变量来描述该内存块被其他Cstring 引用的情况。有一个对象引用该内存块,就将该数值加一。
Cstring 中专门定义了一个结构体来描述这些信息:
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); }
};
实际使用时,该结构体的所占用的内存块大小是不固定的,在Cstring 内部的内存块头部,放置的是该结构体。从该内存块头部开始sizeof(CstringData) 个BYTE 后才是真正的用于存放字符串的内存空间。这种结构的数据结构的申请方法是这样实现的:
pData = (CStringData*) new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
pData->nAllocLength = nLen;
其中nLen 是用于说明需要一次胜申请的内存空间的大小的。
从代码中可以很容易的看出,如果想申请一个256 个TCHAR 的内存块用于存放字符串,实际申请的大小是:
sizeof(CstringData) 个BYTE + (nLen+1) 个TCHAR
很赞哦! (82)