| 伟龙 的个人资料胡说八道照片日志列表 | 帮助 |
|
3月3日 关于CString中的赋值运算的讨论.昨天发现CString在下列运算时会有问题:
Class A { public: CString szTemp; }; void test() { A a; a.szTemp = "123" testB(&a); } void testB(A *b) { A *c; c = new A; *c= *b; delete c; } 调用了testB 后, a.szTemp就是非法的. 经上网查证,得以下原因,供大家参考:
原因一: 由于Class A没有过载"=",所以在做*c = *b的时候,只是做浅度复制,即:把b指向的memery完全Copy过来,丢给c,这样,就没有调用CString的"="运算,只是把c->szTemp的data指针指向了b-<szTemp的data指针指向的内存,所以当c被delete后,就把c->szTemp的data指针指向的内存释放了,从而导致b->szTemp的data非法. 此问题解决方法:对A过载=.(不止是类内有CString成员的情况要,类内有指针,数组类成员应该也会有这问题) 通过此问题的调试,发现一个CString的一个有意思的地方:
CString szTemp1,szTemp2; 如果我们做szTemp1 = szTemp2;后,会发现szTemp1和szTemp2指向一个数据区.而不是把szTemp2的数据区copy一份给szTemp1;这样就会让我们数据区释放的问题: 假想一:
在CString szTemp;变量szTemp消亡后释放. 疑问: 那给szTemp 赋几次值后,已经找不到原来的数据地址空间了,那怎么释放? 假想二: 在每一次赋值时,把原来的空间释放了,指针指向新的空间. 疑问:如果这样释放,那: CString szTemp1 = "000"; CString szTemp2 = "111"; szTemp1 = szTemp2;//释放"000"那一块空间,指向"111"这一块空间. szTemp2 = "222";//释放"111"这块空间,把szTemp2指向"222"这块空间. 那么,szTemp1指向的地址让释放了,不是无效地址了吗? 显然,以上两种都是不太科学也不太现实的.如果不是这两种,MFC是怎么做的?为什么要那样做? 经查证,应该是这样的:
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); } }; 赋值的时候只是简单的把引用计数加1, nRefs++,然后指向同一内存单元 每一个对象销毁时,先把引用计数减1, nRefs--,然后判断是否为0,如果为0才真正释放 这种处理方式和章斌的猜想符合.
那么这么做有什么好处呢?
我个人认为:由于CString一般是个大数据,如果用memcpy,一会占用大的内存资源,二,用memcpy的效率也低,这样用给地址就可以很好的解决.然后使用优化计数方式,也能正确的释放使用完的内存.个人观点,欢迎讨论.
|
|
|||||
|
|