,所以相安无事。
4、不过这里还有一点注意事项:就是GetBuffer(0)后,新分配的缓冲区长度为原来字符串的长度,即指针pszTemp它所指向的缓冲区,给它赋值时,切不可越界。
另外,当调用GetBuffer(...)后并改变其内容,一定要记得调用ReleaseBuffer(),这个函数会根据串内容来更新引用内存块的头部信息。
5、最后还有一注意事项,看下述代码:
char* p = NULL;
const char* q = NULL;
{
CString str = "abcd";
q = (LPCTSTR)str;
p = str.GetBuffer(20);
AfxMessageBox(q);// 合法的
strcpy(p, "this is test");//合法的,
}
AfxMessageBox(q);// 非法的
strcpy(p, "this is test");//非法的
这里要说的就是,当返回这些指针后,如果CString对象生命结束,这些指针也相应
无效。
下面演示一段代码执行过程
void Test()
{
//str指向一引用内存块(引用内存块的引用计数为1,长度为4,分配长度为4)
CString str("abcd");
//a指向一初始数据状态,
CString a;
//a与str指向同一引用内存块(引用内存块的引用计数为2,长度为4,分配长度为4)
a = str;
//a、b与str指向同一引用内存块(引用内存块的引用计数为3,长度为4,分配长度为4)
CString b(a);
{
//temp指向引用内存块的串首地址。
//(引用内存块的引用计数为3,长度为4,分配长度为4)
LPCTSTR temp = (LPCTSTR)a;
//a、b、d与str指向同一引用内存块
//(引用内存块的引用计数为4,长度为4,分配长度为4)
CString d = a;
//这条语句实际是调用CString::operator=(CString&)函数。
//b指向一新分配的引用内存块。
//(新分配的引用内存块的引用计数为1,长度为5,分配长度为5)
//同时原引用内存块引用计数减1. a、d与str仍指向原引用内存块
//(引用内存块的引用计数为3,长度为4,分配长度为4)
b = "testa";
//由于d生命结束,调用析构函数,导至引用计数减1
//(引用内存块的引用计数为2,长度为4,分配长度为4)
}
//此语句也会导致重新分配新内存块。temp指向新分配引用内存块的串首地址
//(新分配的引用内存块的引用计数为1,长度为0,分配长度为10)
//同时原引用内存块引用计数减1. 只有str仍指向原引用内存块
//(引用内存块的引用计数为1,长度为4,分配长度为4)
LPTSTR temp = a.GetBuffer(10);
//a指向的引用内存块的引用计数为1,长度为0,分配长度为10
strcpy(temp, "temp");
//注意:a指向的引用内存块的引用计数为1,长度为4,分配长度为10
a.ReleaseBuffer();
}
//执行到此,所有的局部变量生命周期都已结束。对象str a b 各自调用自己的析构构
//函数,所指向的引用内存块也相应减1
//注意,str a b 所分别指向的引用内存块的计数均为0,这导致所分配的内存块释放
通过观察上面执行过程,我们会发现CString虽然可以多个对象指向同一引用内块存,
但是它们在进行各种拷贝、赋值及改变串内容时,它的处理是很智能并且非常安全的,完全
做到了互不干涉、互不影响。当然必须要求你的代码使用正确恰当,特别是实际使用中会有
更复杂的情况,如做函数参数、引用、及有时需保存到CStringList当中,如果哪怕有一小
块地方使用不当,其结果也会导致发生不可预知的错误
1.3. FreeExtra()的作用
看这段代码
(1) CString str("test");
(2) LPTSTR temp = str.GetBuffer(50);
(3) strcpy(temp, "there are 22 character");
(4) str.ReleaseBuffer();
(5) str.FreeExtra();
上面代码执行到第(4)行时,大家都知道str指向的引用内存块计数为1,长度为22,分配长
度为50. 那么执行str.FreeExtra()时,它会释放所分配的多余的内存。(引用内存块计数为
1,长度为22,分配长度为22)
1.4. Format(...) 与 FormatV(...)
这条语句在使用中是最容易出错的。因为它最富有技巧性,也相当灵活。实际上sprintf(...)怎么用,它就怎么用。但是有一点需要注意:就是它的参数的特殊性,由于编译器在编译时并不能去校验格式串参数与对应的变元的类型及长度。所以你必须要注意,两者一定要对应上,
否则就会出错。如:
CString str;
int a = 12;
str.Format("first:%l, second: %s", a, "error");//result 试试
1.5. LockBuffer() 与 UnlockBuffer()
顾名思议,这两个函数的作用就是对引用内存块进行加锁及解锁。
但使用它有什么作用及执行过它后对CString串有什么实质上的影响。其实挺简单,看下
面代码:
(1) CString str("test");
(2) str.LockBuffer();
(3) CString temp = str;
(4) str.UnlockBuffer();
(5) str.LockBuffer();
(6) str = "error";
(7) str.ReleaseBuffer();
执行完(3)后,与通常情况下不同,temp与str并不指向同一引用内存块。你可以在watch
窗口用这个表达式(CStringData*)((CStringData*)(str.m_pchData)-1)看看。
1.6. AllocSysString()与SetS