String类---深拷贝,简洁深拷贝,引用计数拷贝,写时拷贝
来源:互联网 发布:淘宝助手创建宝贝模板 编辑:程序博客网 时间:2024/06/05 07:23
String类型是c++中非常重要的一个类型,标准库中有String类型,但使用时必须包含它的头文件 #include < String > ,现在我们要模拟String类,实现字符串拷贝。
一、浅拷贝
String::String(const String& s)//浅拷贝:_str(s._str){}int main(){ String s1("1111"); String s2(s1); return 0;}
分析:
s1和s2指向同一块空间,析构时先释放s2,即释放掉这段空间,s1变为野指针,因此在释放s1时会出错,程序崩溃。总之,这段空间被释放了两次会出错。这就是浅拷贝的问题。
并且,当使用以下形式拷贝时,同样会出现问题:
int main(){ String s1("1111"); String s2; s2=s1; return 0;}
s1和s2分别开辟了一段空间,当时s2=s1时,s2指向s1这段空间,s2与自己开辟的空间断开,释放时会出错,程序崩溃。所以,我们同样要对“=”进行重载。
二、深拷贝
class String//深拷贝{public: String(const char* pStr="") { if(NULL==pStr) { _pStr=new char[1]; *_pStr='\0'; } else { _pStr=new char[strlen(pStr)+1]; strcpy(_pStr,pStr); } } String(const String& s) :_pStr(new char[strlen(s._pStr)+1])//申请同样大小的空间 { strcpy(_pStr,s._pStr);//将s1内容拷贝至s2 } ~String() { if(_pStr) { delete[] _pStr; _pStr=NULL; } } String& operator=(const String& s) { if(this!=&s) { char* str=new char[strlen(s._pStr)+1];//开辟同样s1大小的新空间 strcpy(str,s._pStr);//拷贝s1的内容到新空间 delete[] _pStr;//释放s2 _pStr=str;//让s2指向新空间 } return *this; }private: char* _pStr;};int main(){ String s1("1111"); String s2(s1); return 0;}
测试时:
可以看到,s1、s2分别指向不同的空间,因此释放空间时不会出错。并且,深拷贝中对“=”的重载使程序支持链式访问,即s3=s2=s1.
三、简洁深拷贝
class String//简洁版深拷贝{public: String(const char* pStr="") { if(NULL==pStr) { _pStr=new char[1]; *_pStr='\0'; } else { _pStr=new char[strlen(pStr)+1]; strcpy(_pStr,pStr); } } String(const String& s) :_pStr(NULL) { String str(s._pStr); std::swap(_pStr,str._pStr); } ~String() { if(_pStr) { delete[] _pStr; _pStr=NULL; } } String& operator=(const String& s) { if(this!=&s) { String str(s._pStr); std::swap(_pStr,str._pStr); } return *this; }private: char* _pStr;};
简洁深拷贝实际只是将拷贝构造函数和赋值运算符重载写成了更现代的方法。
四、引用计数拷贝
原理:成员变量为_pStr,_pCount,每次赋值时,_pCount+1即又多了一个对象使用这段空间,所以,当每调用析构函数时,_pCount-1,当减至零时,表示没有对象使用这段空间,可以释放。
class String//引用计数拷贝{public: String(const char* pStr="") :_pCount(new int(1)) { if(NULL==pStr) { _pStr=new char[1]; *_pStr='\0'; } else { _pStr=new char[strlen(pStr)+1]; strcpy(_pStr,pStr); } } String(const String& s) :_pStr(s._pStr) ,_pCount(s._pCount) { ++(*_pCount); } ~String() { if(0==--(*_pCount) && _pCount) { delete[] _pStr; delete _pCount; _pStr=NULL; _pCount=NULL; } } String& operator=(const String& s) { if(_pStr!=s._pStr) { if(0==--(*_pCount)) { delete[] _pStr; delete _pCount; } _pStr=s._pStr; _pCount=s._pCount; ++(*_pCount); } return *this; }private: char* _pStr; int* _pCount;//引用计数};
五、写时拷贝cow:在写的时候才会开辟空间
class String//写时拷贝{public: String(char* pStr="") { if(pStr==NULL) { _pStr=new char[1+4]; _pStr+=4; *_pStr='\0'; } else { _pStr=new char[strlen(pStr)+1+4]; _pStr+=4;//往后移动4字节 strcpy(_pStr,pStr);//拷贝内容 } GetCount()=1; } String(const String& s):_pStr(s._pStr) { ++GetCount();//每次调用计数+1 } String& operator=(const String& s) { Release();//释放原来的空间 _pStr=s._pStr; ++GetCount(); return *this; } ~String() { Release(); } char& operator[](size_t index) { if(GetCount()>1) { char* temp=new char[strlen(_pStr)+1+4]; temp+=4; strcpy(temp,_pStr); --GetCount();//原来的计数减1 _pStr=temp; GetCount()=1;//重新开辟的空间计数为1 } return _pStr[index]; } int& GetCount()//获取计数器次数 { return *((int*)_pStr-1);//向前移动了4字节 } void Release()//释放空间 { if(0==--GetCount())//1人使用时,删除 { _pStr-=4;//指针向前移4字节 delete[] _pStr; _pStr=NULL; } }private: char* _pStr;};
0 0
- String类---深拷贝,简洁深拷贝,引用计数拷贝,写时拷贝
- String类详解(浅拷贝,深拷贝,引用计数,写时拷贝)
- String类的浅拷贝、深拷贝、引用计数、写时拷贝
- String类(深/浅拷贝、引用计数、写时拷贝)
- string类,浅拷贝,深拷贝(简洁版),写时拷贝
- C++::浅拷贝,深拷贝,引用计数的拷贝,写时拷贝
- string类深拷贝,写时拷贝
- String类 (浅拷贝/深拷贝/写时拷贝)
- 浅析深拷贝之写时拷贝&引用计数
- 深浅拷贝&引用计数写时拷贝
- String--引用计数写时拷贝
- String-引用计数的写时拷贝
- string引用计数的写时拷贝
- 由深拷贝与浅拷贝引发的引用计数、写时拷贝技术
- 由深拷贝与浅拷贝引发的引用计数、写时拷贝技术
- String类的拷贝(浅拷贝,深拷贝,写时拷贝)
- 用string剖析浅拷贝、深拷贝、写时拷贝
- 引用计数+写时拷贝
- Elasticsearch中mapping的_source和store介绍
- Calendar使用方法(转载)
- 机器学习 SVM sklearn
- 3.16(c程序实现)特殊的平衡二叉搜索树之完全二叉搜索树
- 大数据学习--beginning
- String类---深拷贝,简洁深拷贝,引用计数拷贝,写时拷贝
- Algorithms, 4th Edition 配套学习网站
- tableau中SQL语句根据sql还是access数据库是有区别的
- 什么是Spring,IOC是什么?DI是什么?
- Reverse String
- xposed hook入门篇
- 快速入门Vue.js
- [BZOJ1211][HNOI2004]树的计数(prufer序列+数学相关)
- Odd sum CF