字符类->浅拷贝与深拷贝
来源:互联网 发布:长江证券开户软件下载 编辑:程序博客网 时间:2024/05/18 00:03
首先就深浅拷贝的问题做一个解释;
所谓浅拷贝,也称位拷贝,就是在类中拷贝构造函数以及赋值运算符重载时。通过直接将指针的值拷贝,与原对象共用一个空间;
而深拷贝,在以所述的两种函数中重新申请一块空间存放新的对象;
系统自动生成的拷贝构造即为浅拷贝;
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(s._pStr) { } String& operator=(const String& s) { if (this != &s) { delete[]_pStr; _pStr = s._pStr; } return *this; } ~String() { delete[]_pStr; _pStr = NULL; }private: char* _pStr;};
在这种浅拷贝的情况下,不难发现当析构时由于浅拷贝会对同一块空间两次释放,为了避免这种情况,我们对这种浅拷贝进行改造:带有引用计数,用指针指向引用计数的空间;
private: char* _pStr; int* _pCount;
添加一个新的成员:一个整型指针用来存放当前指向同一空间的对象个数
首先是构造函数与拷贝构造函数:
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); } *_pCount=1; } String(const String &s)//拷贝构造 :_pStr(s._pStr) , _pCount(s._pCount) { (*_pCount)++;//注意优先级 }
赋值运算符重载时,需注意原对象的空间是否还有其他对象在使用,若无便释放,若有则计数减一;
代码如下:
String& operator=(const String& s) { if (this != &s) { if (0 == --(*_pCount)) { delete[]this; } _pStr = s._pStr; _pCount = s._pCount; (*_pCount)++; } return *this; }
最后是析构函数,检测计数是否为一,判断是否释放空间
~String() { if (0 == --(*_pCount)) { delete[]_pStr; delete[]_pCount; _pStr = NULL; _pCount = NULL; } }
这种使用计数指针的方法可以避免浅拷贝的出错,但多出一个指针成员终归是不理想的,参考new[]的做法,我们可以将这个计数放在所申请的空间前,只需多申请4个字节以及做一些处理;
class String{public: String(const char* pStr = "") :_pStr(new char[strlen(pStr) + 4+1]) { *((int *)_pStr) = 1; _pStr += 4; strcpy(_pStr, pStr); } String(const String &s) :_pStr(s._pStr) { ++(*((int *)(_pStr - 4))); } String& operator=(const String& s) { if (this != &s) { if (0 == --(*((int *)(_pStr - 4)))) { _pStr -= 4; delete[] _pStr; } _pStr = s._pStr; ++(*((int *)(_pStr - 4))); } return *this; } ~String() { if (0 == --(*((int *)(_pStr - 4)))) { _pStr -= 4; delete[]_pStr; _pStr = NULL; } }private: char* _pStr;};
下面介绍深拷贝
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); } String& operator=(const String& s) { if (this != &s) { char* pTemp = new char[strlen(s._pStr) + 1]; strcpy(pTemp, s._pStr); delete[]_pStr; _pStr = pTemp; } return *this; } ~String() { delete[]_pStr; _pStr = NULL; }private: char* _pStr;};
与浅拷贝原始函数相比,仅拷贝构造函数与赋值运算符重载需要修改
再运用swap函数对其改造
String(const String &s) :_pStr(NULL) { String str(s._pStr); swap(_pStr, str._pStr); }
修改后的拷贝构造,需注意要将_pStr赋空指针,否则会造成销毁野指针而出错;
String& operator=(String s) { swap(_pStr, s._pStr); return *this; }
赋值运算符重载中,利用拷贝构造一个s,出函数时会对其进行析构,函数中利用s对this中的指针进行交换赋值。
1 0
- 字符类->浅拷贝与深拷贝
- 类的深拷贝与浅拷贝
- 深拷贝与浅拷贝
- 深拷贝与浅拷贝
- 深拷贝与浅拷贝
- “浅拷贝”与“深拷贝”
- 深拷贝与浅拷贝
- 深拷贝与浅拷贝
- 深拷贝与浅拷贝
- 浅拷贝与深拷贝
- 深拷贝与浅拷贝
- 深拷贝与浅拷贝
- “浅拷贝”与“深拷贝”
- 深拷贝与浅拷贝
- 浅拷贝与深拷贝
- 深拷贝与浅拷贝
- 浅拷贝与深拷贝
- 深拷贝与浅拷贝
- 学习日志第14篇
- java之StringBuider与StringBuffer
- R实用 编程资料
- 心算技巧
- this,super
- 字符类->浅拷贝与深拷贝
- KSH comparison operator
- Matlab GUI 设计(4):不同控件之间的数据传递
- Apache配置本地虚拟域名
- 基于Android移动终端的微型餐饮管理系统的设计与实现1-简介
- JavaScript入门<3>JS外置对象:Window、Document对象与DOM实例详解
- 开发环境、生产环境、测试环境的基本理解和区别
- ksh regular expression pattern
- 用WinHex软件解析FAT32文件系统