您当前位置:地名问答 > 中国 > 浙江 > 杭州 > 西湖区 > 断桥残雪 > 断桥残雪地名
CString需要注意的地方(4)
更新:2017-08-18 01:51【断桥残雪地名】
导读:通过设置断点,我们来运行并跟踪这段代码可以看出,当运行到三处时, str1 的值是 This is the string 1, 并且 nOldLen 的值是 20 。当运行到 5 处时,发现, s
通过设置断点,我们来运行并跟踪这段代码可以看出,当运行到三处时,str1 的值是”This is the string 1”, 并且nOldLen 的值是20 。当运行到5 处时,发现,str1 的值变成了”modified” 。也就是说,对GetBuffer 返回的字符串指针,我们将它做为参数传递给strcpy ,试图来修改这个字符串指针指向的地址,结果是修改成功,并且Cstring 对象str1 的值也响应的变成了” modified” 。但是,我们接着再调用str1.GetLength() 时却意外的发现其返回值仍然是20 ,但是实际上此时str1 中的字符串已经变成了” modified”, 也就是说这个时候返回的值应该是字符串” modified” 的长度8 !而不是20 。现在Cstring 工作已经不正常了!这是怎么回事?很显然,str1 工作不正常是在对通过GetBuffer 返回的指针进行一个字符串拷贝之后的。
再看MSDN 上的关于这个operation 的说明,可以看到里面有这么一段话:
If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before using any other CString member functions.
原来在对GetBuffer 返回的指针使用之后需要调用ReleaseBuffer ,这样才能使用其他Cstring 的operations 。上面的代码中,我们在4 -5 处增建一行代码:str2.ReleaseBuffer(), 然后再观察nNewLen, 发现这个时候已经是我们想要的值8 了。
从Cstring 的机理上也可以看出:GetBuffer 返回的是CstringData 对象里的字符串缓冲的首地址。根据这个地址,我们对这个地址里的值进行的修改,改变的只是CstringData 里的字符串缓冲中的值, CstringData 中的其他用来描述字符串缓冲的属胜的值已经不是正确的了。比如此时CstringData:: nDataLength 很显然还是原来的值20 ,但是现在实际上字符串的长度已经是8 了。也就是说我们还需要对CstringData 中的其他值进行修改。这也就是需要调用ReleaseBuffer() 的原因了。
正如我们所预料的,ReleaseBuffer 源代码中显示的正是我们所猜想的:
CopyBeforeWrite(); // just in case GetBuffer was not called
if (nNewLength == -1)
nNewLength = lstrlen(m_pchData); // zero terminated
ASSERT(nNewLength <= GetData()->nAllocLength);
GetData()->nDataLength = nNewLength;
m_pchData[nNewLength] = '/0';
其中CopyBeforeWrite 是实现写拷贝技术的,这里不管它。
下面的代码就是重新设置CstringData 对象中描述字符串长度的那个属胜值的。首先取得当前字符串的长度,然后通过GetData() 取得CstringData 的对象指针,并修改里面的nDataLength 成员值。
但是,现在的问题是,我们虽然知道了错误的原因,知道了当修改了GetBuffer 返回的指针所指向的值之后需要调用ReleaseBuffer 才能使用Cstring 的其他operations 时,我们就能避免不在犯这个错误了。答案是否定的。这就像虽然每一个懂一点编程知识的人都知道通过new 申请的内存在使用完以后需要通过delete 来释放一样,道理虽然很简单,但是,最后实际的结果还是有由于忘记调用delete 而出现了内存泄漏。
很赞哦! (82)