4 经验总结:预防措施和规范建议
STL中为了提高性能大量采用写时才拷贝(Copy-On-Write)技术,该技术使用了"引用计数",有一个变量类似于RefCnt。当第一个类构造时,string的构造函数会根据传入的参数从堆上分配内存,当有其它对象被拷贝构造时候它们会共享这块内存,这个计数会自动累加,当有对象被析构时,这个计数会减一,直到最后一个对象析构时,此时的RefCnt为1或是0,此时,程序才会真正的Free这块从堆上分配的内存。在共享同一块内存的对象发生内容改变时,就会发生Copy-On-Write,比如string类的[]、=、+=、+、操作符赋值,还有string类中诸如insert、replace、append等成员函数,发生Copy-On-Write时候string类的拷贝构造函数会重新分配一块内存区,将新的内容写入新的内存区间中,并将原有内存区间的引用计数减一。
在使用STL时候了解STL中的Copy-On-Write技术,避免在使用STL中的类时候引起一些内存问题。在Windows下、Linux、Solaris下都存在这种机制,AIX下则没有使用这种机制。
5 备注
STL库其他容器也有类似的问题需要注意;下面是string类的构造函数和拷贝构造函数以及重载操作符函数代码,供参考,里面真实表现了copy-on-write和共享内存技术;
//构造函数(分存内存)
string::string(const char* tmp)
{
_Len = strlen(tmp);
_Ptr = new char[_Len+1+1];
strcpy( _Ptr, tmp );
_Ptr[_Len+1]=0; // 设置引用计数
}
//拷贝构造(共享内存)
string::string(const string& str)
{
if (*this != str)
{
this->_Ptr = str.c_str(); //共享内存
this->_Len = str.szie();
this->_Ptr[_Len+1] ++; //引用计数加一
}
}
//写时才拷贝Copy-On-Write
char& string::operator[](unsigned int idx)
{
if (idx > _Len || _Ptr == 0 )
{
static char nullchar = 0;
return nullchar;
}
_Ptr[_Len+1]--; //引用计数减一
char* tmp = new char[_Len+1+1];
strncpy( tmp, _Ptr, _Len+1);
_Ptr = tmp;
_Ptr[_Len+1]=0; // 设置新的共享内存的引用计数
return _Ptr[idx];
}
6 考核点
Copy-on-Write机制
7 试题
关于下面这段代码(VC6.0)的结果说法正确的是:(D)
main()
{
string str1 = "hello world";
string str2 = str1;
printf ("address1: %x\n", str1.c_str() );
printf ("address2: %x\n", str2.c_str() );
str1[1]='a';
printf ("address3: %x\n", str1.c_str() );
str2[2]='b';
printf ("address4: %x\n", str2.c_str() );
return 0;
}
A. 由于str1和str2是2个不同的对象,所以address1和address2不一致;
B. address3和address1的内存地址空间一致;
C. address3和address4的内存地址空间一致;
D. address1和address3的内存地址空间不一致。
阅读(268) | 评论(0) | 转发(0) |