深浅拷贝与写时拷贝的简单认知
来源:互联网 发布:ubuntu u盘 编辑:程序博客网 时间:2024/06/06 07:15
深浅拷贝
1.什么是浅拷贝?里面存在什么问题?
解:浅拷贝也称位拷贝,编译器只是将指针的值拷贝过来。然后会导致多个对象共用同一块空存,当一个对象将这块内存释放掉之后,另一些对象不知道该空间已经还给了系统,以为还有效,所以在对这段内存进行操作的时候,发生了访问违规。
下面来具体看一下有关浅拷贝的代码:
#include <iostream>#include <string>using namespace std;class String{public: //构造函数 String(char *str = "") :_str(str) {} //修改后的构造函数 String(char *str = "")//构造函数 { if (NULL == str) { _str = new char[1];//为了和delete[]配合使用 *_str = '\0'; } else { _str = new char[strlen(str) + 1]; strcpy(_str, str); } } //拷贝构造函数(浅拷贝)程序会崩溃(同一空间被释放多次) String(const *String &s) :_str(s._str) {} //拷贝构造函数(深拷贝)重新开辟空间 String(const *String &s) :_str(new char[strlen(s._str)+1]) { strcpy(_str, s._str); } //赋值运算符重载 //方法一 (先释放,再开辟空间,但空间开辟可能会失败,不仅没有将s1赋值给s2,还易破坏原来的s2) String& operator = (const String& s) { if(this != &s) { delete[] _str; _str = new char[strlen(s._str)+1]; strcpy(_str, s._str); } return *this; } //方法二(先开辟空间,赋值,再释放,不用担心破坏原来的对象) String& operator = (const String& s) { if(this != NULL) { char* temp = new char[strlen(s._str)+1]; strcpy(temp, s.-str); delete[] _str; _str = temp; } return *this; }//析构函数~String(){ if(NULL != _str) { delete[] _str; }}private: //数据成员 char *_str;};
注:
当类里有指针对象是,拷贝构造函数和赋值运算符重载只进行值拷贝(浅拷贝),两个对象指向同一块内存,对象销毁时该空间被释放了两次,所以程序崩溃。
2.用深拷贝怎么解决上面浅拷贝出现的问题?
解:构造s2时拷贝一块跟s1指向数据块一样大的数据块,并将值拷贝下来,这样s1和s2指向各自的数据块,析构时释放各自的数据块。
下面同样来看一下深拷贝的代码:
#include <iostream>using namespace std;class String{public: //构造函数 String(char* str = "") :_str(new char[strlen(str) + 1]) { strcpy(_str, str); } //拷贝构造函数 String(const String& s) { this->_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; } }private: char* _str;};
写时拷贝—Copy On Write
引用计数,像new开辟空间那样对开辟四个字节保存计数数字
注:有几块空间就有几个计数
3.什么是引用计数?
解:在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。
首先来看一下引用计数的代码(ps:代码可能不太成熟,还在研究完善ing)
#include <iostream>using namespace std;class String{public: String(const char* str = "") { if(NULL = str) { _str = new char[1]; *str = '\0'; } else { _str = new char[strlen(str)+1]; strcpy(_str, str); } _count = 1; } String(String &s) :_str(s._str) ,_count(++(s._count)) { strcpy(_str, s._str); } ~String() { //_count是每个对象的,减去一个共享一块空间的其中一个对象的成员 //并不会改变其他对象的成员变量_count的值 if((--_count == 0)&&(NULL != _str)) { cout<<this<<endl; delete[] _str; } }private: char *_str;};
然后看一下写时拷贝的代码:
String.h#include <iostream>#include <assert.h>using namespace std;class String{public: //构造函数 String(const char* str = "") { if(NULL == str) { char* temp =new char[1+3]; _pStr = temp + 4; _GetRefer() = 1; *_pStr = '\0'; } else { char* temp = new char[strlen(str)+1+3]; _pStr = temp + 3; strcpy(_pStr, str); _GetRefer() = 1; } } //拷贝构造函数 String(const String& s) :_pStr(s._pStr) { _GetRefer()++; } //析构函数 ~String() { Release(); } String& operator=(const String& s); char& operator[](size_t index); const char& operator[](size_t index)const; int& String::_GetRefer(); void Release(); friend ostream& operator<<(ostream& _cout, const String& s);private: char *_str;}String.cpp //运算符重载 String& String:: operator = (const String &s) { if(_pStr != s._pStr) { if(--_GetRefer() == 0) { Release(); _pStr = s._pStr; _GetRefer()++; } else { _pStr = s._pStr; _GetRefer()++; } } return *this; }//获取引用计数int& String ::_GetRefer(){ return *((int*)_pStr-1);}//释放空间void String ::Release(){ if(--_GetRefer() == 0) { _pStr -= 3; delete[] _pStr; _pStr == NULL; }}//成对出现char* String ::operator [](size_t index){ if(_GetRefer() > 1) { _GetRefer()--; char* temp = new char[strlen(_pStr)+1+3]; temp += 3; strcpy(temp, _pStr); -pStr = temp; _GetRefer() = 1; //(新开的空间) } return _pStr[index];}const char* String ::operator [](size_t index)const{ return _pStr[index];}void Test1(){ const String s1("hello"); String s2(s1); //String s3; //s3 = s2; cout << s1[4] << endl;}int main(){ Test1(); return 0;}
注:有几块空间就有几个计数
今天就先学习到这里,还有好多要完善,会继续改进!!!(ps:欢迎大家指正错误,共同进步) 纸上得来终觉浅,绝知此事要躬行。
阅读全文
0 0
- 深浅拷贝与写时拷贝的简单认知
- 深浅拷贝与写时拷贝
- string的深浅拷贝以及写时拷贝问题
- c++深浅拷贝&写时拷贝实现
- C++String深浅拷贝、写时拷贝
- 深浅拷贝和写时拷贝
- 深浅拷贝&引用计数写时拷贝
- String类的自我认知(浅拷贝、深拷贝、写时拷贝)
- C++中的深浅拷贝和写时拷贝
- 【c++】深浅拷贝,引用计数写时拷贝
- copy 的实现原理与深浅拷贝
- C++与Python的深浅拷贝比较
- copy 的实现原理与深浅拷贝
- NSString与NSMutableString的深浅拷贝
- python的赋值与深浅拷贝
- ArrayList的深浅拷贝。
- 深浅拷贝的理解
- 深浅的拷贝
- Android网络:发送http请求
- 【51Nod1765】谷歌的恐龙
- Mac系统之----教你怎么显示隐藏文件,或者关闭显示隐藏文件
- 怎么会有两个“原本”
- C++中链表的创建、输出、节点删除、节点插入、翻转、清空
- 深浅拷贝与写时拷贝的简单认知
- mysql Community Server 5.7安装教程以及常见错误
- Java 9 新特性之模块化和进程API
- 智慧城市建设概述
- [设计模式]职责链模式
- Redis系列-7.有序集合(zset)结构
- X86 指令速查
- android自定义ViewGroup卫星导航菜单
- dp