伟龙 的个人资料胡说八道照片日志列表 工具 帮助

日志


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的效率也低,这样用给地址就可以很好的解决.然后使用优化计数方式,也能正确的释放使用完的内存.个人观点,欢迎讨论.

 

评论

请稍候...
很抱歉,您输入的评论太长。请缩短您的评论。
您没有输入任何内容,请重试。
很抱歉,我们当前无法添加您的评论。请稍后重试。
若要添加评论,需要您的家长授予您相应权限。请求权限
您的家长禁用了评论功能。
很抱歉,我们当前无法删除您的评论。请稍后重试。
您已超过了一天之内允许提供的评论数上限。请在 24 小时后重试。
因为我们的系统表明您可能在向其他用户提供垃圾评论,您的帐户已禁用了评论功能。如果您认为我们错误地禁用了您的帐户,请联系 Windows Live 支持部门
完成下面的安全检查,您提供评论的过程才能完成。
您在安全检查中键入的字符必须与图片或音频中的字符一致。

若要添加评论,请使用您的 Windows Live ID 登录(如果您使用过 Hotmail、Messenger 或 Xbox LIVE,您就拥有 Windows Live ID)。登录


还没有 Windows Live ID 吗?请注册

引用通告

此日志的引用通告 URL 是:
http://wlzhou327.spaces.live.com/blog/cns!8C942C1577AEC164!111.trak
引用此项的网络日志