浅拷贝、深拷贝与写时拷贝
来源:互联网 发布:09和冷冷的故事 知乎 编辑:程序博客网 时间:2024/06/13 19:32
浅拷贝、深拷贝与写时拷贝
浅拷贝
- 在默认拷贝构造函数中,拷贝的策略是逐个成员依次拷贝。
- 如果拷贝构造函数简单地制作了一个该对象的拷贝,而不对它的本身进行资源分配和复制,就得面临一个麻烦的局面。
- 即,两个对象都拥有同一个资源。
- 当对象析构时,该资源将经历两次资源返还。
- 创建p2时,对象p1被复制给了p2,但资源并未复制,因此,p1和p2指向同一个资源。
- 这便被称为,浅拷贝。
深拷贝
- 当一个对象创建时,分配了资源,这时,就需要定义自己的拷贝构造函数,使之不但拷贝成员,也分配和拷贝资源。
- 创建p2时,对象p1被复制给了p2,同时资源也作了复制。
- 因此,p1和p2指向不同的资源。
这,便被称为深拷贝。
如果你的类需要析构函数来析构资源,则它也需要一个拷贝构造函数。
因为对象通常是自动被析构的。
如果需要一个自定义的析构函数,那就意味着有额外资源要在对象被析构之前释放。
此时,对象的拷贝就不是浅拷贝了。深拷贝代码实现
#include<iostream>#include<string.h>#define _CRT_SECURE_NO_WARNINGS#pragma warning( disable : 4996)using namespace std;传统写法class String{public: String(char* str = "") :_str(new char[strlen(str)+1]) { strcpy(_str, str); } String(const String& s) { _str = new char[strlen(s._str) + 1]; strcpy(_str, s._str); } String& operator=(const String& s) { if (this != &s) { delete[] _str; _str = new char[strlen(s._str) + 1]; strcpy(_str, s._str); } return *this; } ~String() { if (_str) { delete[] _str; } } char* GetStr() { return _str; }private: char* _str;};//现代写法class String{public: String(char* str) :_str(new char[strlen(str) + 1]) { strcpy(_str, str); } String(const String& s) :_str(NULL) { String tmp(s._str); swap(_str, tmp._str); } String& operator=(String s) { swap(_str, s._str); return *this; } ~String() { if (_str) { delete[] _str; } } char* GetStr() { return _str; }private: char* _str;};
写时拷贝
- 基于浅拷贝和深拷贝延伸出的写时拷贝具有更好的实用性。
- 在只需要进行 只读 操作时,执行浅拷贝。
- 而在需要进行 写 操作时,则执行深拷贝。
- 写时拷贝有两种方案可以实现,可根据自身需要进行取舍。
方案一
- 增加一个类成员 _refCountPtr,用来表示同一个堆有几个对象指向。
- 以便调用析构函数,防止空间被多次释放,或者部分空间未释放。
namespace COW1{ class String { public: String(const char*str) //构造函数 :_refCountPtr(new int(1)) { _size = strlen(str); _capacity = _size; _str = new char[strlen(str) + 1]; strcpy(_str, str); } String(const String& s) //拷贝构造函数 :_str(s._str) , _size(s._size) , _capacity(s._capacity) , _refCountPtr(s._refCountPtr) { (*_refCountPtr)++; } ~String() //析构函数 { Release(); } //s1 = s2 String& operator=(const String& s) //运算符的重载 { if (_str != s._str) { Release(); _str = s._str; _refCountPtr = s._refCountPtr; (*_refCountPtr)++; } return *this; } void Release() { if (--(*_refCountPtr) == 0) { cout << "Release!" << endl; delete[] _str; delete _refCountPtr; } } void CopyOnWrite() //写时拷贝 { if (*_refCountPtr > 1) { char* NewStr = new char[_capacity + 1]; strcpy(NewStr, _str); (*_refCountPtr)--; _str = NewStr; _refCountPtr = new int(1); } } char& operator[](size_t pos) { CopyOnWrite(); return _str[pos]; } char operator[](size_t pos) const { return _str[pos]; } const char* c_str() { return _str; } private: char* _str; int* _refCountPtr; size_t _size; size_t _capacity; };}
方案二
- 使用引用计数,将引用计数放在字符串的头四个字节中。
- 使得,每个对象都能有不同的引用计数。
namespace COW2{ class String { public: String(const char* str) :_str(new char[strlen(str)+5]) { strcpy(_str+4, str); _str += 4; GetRefCount() = 1; } String(const String& s) :_str(s._str) { GetRefCount()++; } ~String() { Release(); } void Release() { if (--GetRefCount() == 0) { delete[] (_str-4); } } void CopyOnWrite() { if (GetRefCount() > 1) { char* NewStr = new char[_capacity + 1]; strcpy(NewStr, _str); GetRefCount()--; _str = NewStr; GetRefCount() = 1; } } String& operator = (const String& s) { if (_str != s._str) { Release(); _str = s._str; GetRefCount()++; } return *this; } char& operator[](size_t pos) { CopyOnWrite(); return _str[pos]; } char operator[](size_t pos)const { return _str[pos]; } int& GetRefCount() { return *((int*)(_str - 4)); } const char* c_str() { return _str; } const char* GetStr() { return _str; } private: char* _str; size_t _size; size_t _capacity; };}
阅读全文
0 0
- 深拷贝&浅拷贝&写时拷贝
- 浅拷贝、深拷贝与写时拷贝
- 浅拷贝、深拷贝(普、简)、写时拷贝
- 【C++】深拷贝、浅拷贝和写时拷贝
- c++深拷贝、浅拷贝、写时拷贝
- 用string剖析浅拷贝、深拷贝、写时拷贝
- String类 (浅拷贝/深拷贝/写时拷贝)
- 由深拷贝与浅拷贝引发的引用计数、写时拷贝技术
- 由深拷贝与浅拷贝引发的引用计数、写时拷贝技术
- 深拷贝与浅拷贝
- 深拷贝与浅拷贝
- 深拷贝与浅拷贝
- “浅拷贝”与“深拷贝”
- 深拷贝与浅拷贝
- 深拷贝与浅拷贝
- 深拷贝与浅拷贝
- 浅拷贝与深拷贝
- 深拷贝与浅拷贝
- 简单了解Effective java
- 单链表一些总结
- Gym-100820 Racing Gems(二维LIS)
- Alice, Bob, Two Teams CodeForces
- mysql row模式的一些小问题(一)
- 浅拷贝、深拷贝与写时拷贝
- Integer源码(toHexString).md
- 构造代码块笔记
- ActiveMQ实战(三)--ActiveMQ的通信方式之主题发布订阅式(publish-subscribe)
- Codeforces 822C Hacker pack your bags! 区间
- 多态笔记
- android 网格布局
- Leetcode 111. Minimum Depth of Binary Tree
- gym 101170 NWERC 2016 J Jupiter Orbiter