写时拷贝的两种方案
来源:互联网 发布:知乎日本海外球员名单 编辑:程序博客网 时间:2024/06/10 11:35
1. 什么是写时拷贝
写时拷贝故名思意:是在写的时候(即改变字符串的时候)才会真正的开辟空间拷贝(深拷贝),如果只是对数据的读时,只会对数据进行浅拷贝。写时拷贝:引用计数器的浅拷贝,又称延时拷贝:写时拷贝技术是通过"引用计数"实现的,在分配空间的时候多分配4个字节,用来记录有多少个指针指向块空间,当有新的指针指向这块空间时,引用计数加一,当要释放这块空间时,引用计数减一(假装释放),直到引用计数减为0时才真的释放掉这块空间。当有的指针要改变这块空间的值时,再为这个指针分配自己的空间(注意这时引用计数的变化,旧的空间的引用计数减一,新分配的空间引用计数加一)。
2. string中的两种写时拷贝
一:
- 动态开辟两个空间一个用来存放字符串:_str,一个用来存放计数器_refCountPtr
- 每次拷贝构造时(赋值运算符的重载后半段),直接把字符串的指针付给新的String,然后给计数器加加(*_refCountPtr)++
- 在释放String的时候,先对计数器减减,再判断计数器是否为零(即看是否还有指针共享此内存),若计数器为零则直接释放_str 和 _refCountPtr
- 在对字符串进行更改的时候(写时),就要进行深拷贝:先进行步骤3,在进行深拷贝和字符串的更改
class String//写时拷贝 { public: String(char * str = "\0") :_refCountPtr(new int(1))//开辟计数器动态内存 ,_size(strlen(str)) { _capacity = _size; _str = new char[_capacity+1];//开辟字符串动态内存 strcpy(_str,str); } String(String& s)//拷贝构造 :_str(s._str)//直接浅拷贝 ,_refCountPtr(s._refCountPtr) ,_size(s._size) ,_capacity(s._capacity) { (*_refCountPtr)++;//但对计数器 ++ } ~String()//析构 { Release(); } inline void Release() { if(--(*_refCountPtr) == 0)//计数器--,并判断是否为0 { cout<<"~String"<<_str<<endl; delete[] _str; delete _refCountPtr;//释放 } } String &operator=(String &s)//重载 { if(_str != s._str)//判断是否为自己给自己赋值 { Release();//判断并处理this _str = s._str; _refCountPtr = s._refCountPtr; _size = s._size; _capacity = s._capacity; (*_refCountPtr)++; } return *this; } char *c_str() const { return _str; } //写时拷贝 String &push_back(char ch) { char* str = new char[_capacity*2]; strcpy(str,_str); //先将原来的数据保存,用于给后面重新开辟的空间赋值 Release();//处理原来的空间 _str = str; _str[_size++] = ch; _str[_size] = '\0'; _capacity *= 2; _refCountPtr = new int(1);// return *this; } private: char *_str; int *_refCountPtr; size_t _size; size_t _capacity; };
二:
开辟一个空间,前面4个字节为计数器count,剩下的为字符串_str的空间,用法与分开相同。
class String { public: String(char *str = "\0") :_capacity(strlen(str)) { _size = _capacity; _str = new char[_capacity + 5];//多开辟了4个字节 *(int *)_str = 1;//前4个自己存放计数器 _str += 4; //使_str指向开辟的4个字节后的空间 strcpy(_str,str);//拷贝字符串 } String(String &s)//拷贝构造 :_str(s._str)//直接浅拷贝 ,_capacity(s._capacity) ,_size(s._size) { ++(*(int *)(_str-4));//(str前的4个字节为计数器) ++ } ~String()//析构 { Release(); } void Release() { if(--(*(int *)(_str-4)) == 0)//计数器-1判断是否为零 { cout<<"~String "<<_str<<endl; delete[] (_str-4); } } String& operator=(String &s)//赋值重载 { if(_str != s._str)//判断是否为自己为自己赋值 { Release();//处理原指针(释放空间,或者计数器-1) _str = s._str; _size = s._size; _capacity = s._capacity;//赋值 ++(*(int *)(_str-4));//改变先指针的计数器 } return *this; } String &operator+=(char ch)//重载,会改变,会深拷贝 { char* str = new char[_capacity*2 + 6]; strcpy(str+4, _str);//先保存原字符串 Release();//因为要重新开辟空间,所以需要处理以前的空间 *(int *)str = 1;//新开辟的计数器置1 _str = str + 4; _str[_size++] = ch; _str[_size] = '\0'; _capacity *= 2; return *this; } String &append(const char *str)//追加字符串 { size_t len = strlen(str);//方法同+=的重载 _capacity = len + _size; char *tmp = new char[_capacity + 6]; strcpy(tmp+4 ,_str); Release(); *(int *)tmp = 1; _str = tmp + 4; strcpy(_str+_size, str); _size = _capacity; return *this; } private: char* _str;//开辟多4个,指向4个字节后的地址 size_t _size; size_t _capacity; };
阅读全文
1 1
- 写时拷贝的两种方案
- C++写时拷贝的不同方案(String类)
- 【c++编程思想学习笔记】解决浅拷贝的两种方法:(深拷贝)(引用计数+写拷贝)
- 写时拷贝方案分析 copy on write
- string的写时拷贝
- 两种关闭拷贝构造的手法
- scp 拷贝的两种方法
- Oracle拷贝数据的两种方式
- 拷贝文本文件的两种方式
- C++::浅拷贝,深拷贝,引用计数的拷贝,写时拷贝
- String类的拷贝(浅拷贝,深拷贝,写时拷贝)
- string的深浅拷贝以及写时拷贝问题
- 深浅拷贝与写时拷贝的简单认知
- 深拷贝&浅拷贝&写时拷贝
- string的写时拷贝分析
- fork函数的写时拷贝
- string类的写时拷贝
- String类的写时拷贝
- 怎样让你的QQ空间活跃起来
- 《Linux内核设计与实现》读书笔记(十三)- 虚拟文件系统
- kali免认证登录
- leetcode刷题之判断链表是否是回文链表
- window postgre 调试函数设置
- 写时拷贝的两种方案
- Mac下intellij idea 连接数据库并利用hibernate反向生成实体类
- angularjs方式的get与post分析
- MSP430G2xx1系列USI的SPI模式详解
- flask数据用ECharts图表形式展现
- ViewPager和ViewPager+Fragment简单使用
- mysql事务的理解
- Service使用总结
- Go编程基础—并发(concurrency)