最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
深入理解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,等, 你在使用[]之后再使用迭代器之后,引用就有可能失效了。
-
下一个: 浅谈.NET中接口与类的区别
相关文章
- C#复制数组的两种方式及效率比较解读 10-24
- ASP.NET Identity用法解析 10-24
- ASP.NET MVC使用Identity增删改查用户介绍 10-24
- C语言中atoi函数模拟实现介绍 10-18
- .Net反向代理组件Yarp用法介绍 10-10
- .NET使用YARP通过编码方式配置域名转发实现反向代理教程 10-10