一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

深入理解C/C++中的写时拷贝

时间:2017-08-03 编辑:简简单单 来源:一聚教程网

写时拷贝

何为写时拷贝? 前面我说过深拷贝浅拷贝,今天我们来探究一下写时拷贝。深拷贝是补充了浅拷贝的不足,写时拷贝其实也就是补充一点深拷贝的不足。其实写时拷贝的意思就是: 当你读取到这个空间的时候,并不会开辟出一个一模一样的空间出来给你,当你真正需要拷贝的时候,那么他就会开辟出空间给你。也就是拖延版的深拷贝。

写时拷贝技术是通过"引用计数"实现的,在分配空间的时候多分配4个字节,用来记录有多少个指针指向块空间,当有新的指针指向这块空间时,引用计数加一,当要释放这块空间时,引用计数减一(假装释放),直到引用计数减为0时才真的释放掉这块空间。当有的指针要改变这块空间的值时,再为这个指针分配自己的空间(注意这时引用计数的变化,旧的空间的引用计数减一,新分配的空间引用计数加一)。

写时拷贝的实用:实现一个string类

 代码如下 复制代码

classString

{

public:

 String(constchar*str ="")

 :_str(newchar[strlen(str) + 1 + 4])

 {

 cout <<"Sring()"<< endl;

 _str += 4;   //前4个字节用来存放引用计数

 GetCount() = 1;  //引用计数的初始值设置成1

 strcpy(_str, str);

 }

  

 String(String& s)

 :_str(s._str)

 {

 cout <<"Sring(String&)"<< endl;

 GetCount()++;

 }

  

 String& operator=(String& s)

 {

 cout <<"Sring& operator="<< endl;

  

 if(this!= &s)

 {

  Release();

  _str = s._str;

  GetCount()++;

 }

 return*this;

 }

  

 ~String()

 {

 cout <<"~Sring()"<< endl;

 Release();

 }

public:

 char& operator[](size_tindex)

 {

 if(GetCount() == 1)  //如果计数器为1,则直接返回

 {

  return_str[index];

 }

 GetCount()--;

 char*tmp = _str;

 _str =newchar[strlen(tmp) + 1 + 4];

 _str += 4;

 strcpy(_str, tmp);

 GetCount() = 1;

 return_str[index];

 }

private:

 int& GetCount()

 {

 return*(int*)(_str - 4);

 }

 voidRelease()

 {

 if(--GetCount() == 0)

 {

  cout <<"释放"<< endl;

  delete[](_str - 4);//注意释放的时候还有 存放引用计数的4个字节

  _str = NULL;

 }

 }

private:

 char*_str;

};

这里有一个问题呢~,C++标准的确就是这样的,C++标准认为,当你通过迭代器或[]获取到string的内部地址的时候,string并不知道你将是要读还是要写。这是它无法确定,为此,当你获取到内部引用后,为了避免不能捕获你的写操作,它在此时废止了写时才拷贝技术。

这样看来我们在使用写时拷贝的时候,一定要注意,如果你不需要对string的内部进行修改,那你就千万不要使用通过[]操作符和迭代器去获取字符串的内部地址引用,如果你一定要这么做,那么你就必须要付出代价。当然,string还提供了一些使迭代器和引用失效的方法。比如说push_back,等, 你在使用[]之后再使用迭代器之后,引用就有可能失效了。


热门栏目