深拷贝与写实拷贝----string
2017-03-26 17:55
375 查看
摘要
学过或者了解过C++都知道,,,在C++中面向对象实现一个类 、、、的时候必须要考虑的就是【深浅拷贝】的问题 ??
所以我写了这篇文章来简要的讲述一下C++中深浅拷贝的问题以及由此引发的 另一个 概念【写实拷贝】
概念的解析
所谓的深浅拷贝就是C++中;;;;;定义一个类的时候;;;
其拷贝构造函数、、、还有赋值运算符的重载 的不同的实现方法;;;
当一个类的成员变量中带有的是 指针;;;
当使用这个类对象拷贝生成一个对象的的时候、、、如果直接赋值的话,,,,,类析构的时候就会出现问题;;;
所以在这种时候 我们就需要来考虑深拷贝的问题;;;;
关于深拷贝的问题、、、大致主要有两种的方法:
方法1、
直接重新申请一段相同大小的空间、、、并赋值成相同的值 ;;;
这就是直接的深拷贝;
方法2、
在类的成员变量中加上一个 【引用计数 】用来表示当前有多少个对象在公用一段空间
类析构时、(要是引用计数为1 直接释放这段空间 )(否则的话就将这个对象的成员变量的指针置为NULL)
这种方法 就是 带有引用计数的浅拷贝的 实现深拷贝
【灰常的重要】
但是上述的方法2 虽然实现了 深拷贝 、、、但是还遗留了一个很大的问题;;;
假设有 4 个string类的对象 a b c d;公用的是 同一段的空间
现在要对 对象a 的内容进行修改、、、、
但是要是修改了 a的 内容 b c d的内容也会被修改(因为它们用的是同一段空间)
所以也就出现了 【写实拷贝】这个 概念》》》》
当遇到上述这种情况下、、、、谁 改变 就对谁进行拷贝 ------这就是 写实拷贝
上述的两种方法
Windows系统下的编程环境使用的是 方法1
Linux系统下是用的是 方法2
通常情况下、、、、、我们都是使用的是 string来演示实现 深拷贝、、、与写实拷贝的
代码的实现
下面我来实现这段代码的实现#pragma once #include <assert.h> //说道string类的两个主要考点就是 //深拷贝 //浅拷贝 写实拷贝 () //深拷贝 class String { public: String(const char * str = "") { //要是传进来的字符串为 NULL if(str == NULL) { //我们需要创建一个内容为 /0的字符串 _str =new char [1]; *_str = '/0'; } else { //否则,,,开辟一个长度为 str长度+1; _str = new char [strlen(str)+1]; strcpy(_str,str); } } //深拷贝的拷贝构造函数 //String(const String & str) // :_str(new char[strlen(str._str)+1]) //{ // //先为字符串开辟一个空间 // //将内部的数据拷贝 // strcpy(_str,str._str); //} //简介版 的拷贝构造函数 String (const String & str) :_str(NULL)//现将当前的对象的字符串的指针赋为空 ,,,必须要写 { //使用的是 str内部的字符串的指针,,来构造一个新的对象 str1; String str1(str._str); //将当前的对象的_str 与 重新生成的新对象的_str 交换 swap(_str,str1._str); } //深拷贝的赋值运算符的重载 //String & operator = (const String & str) //{ // if(this!= &str) // { // //开辟一个空间 // char * tmp =new char[strlen(str._str)+1]; // //将原来的空间释放 // delete[]_str; // //将内容拷贝到所开辟的位置 // strcpy(tmp,str._str); // //将开辟的空间给当前的类 // _str = tmp; // } // return *this; //} //简介版 的赋值运算符的重载 String & operator =(const String & str) { //防止自己给自己赋值 if(this != & str) { String str1(str);//使用拷贝构造函数 ,,,来生成一个新的对象 //先将当前对象的_str释放 ,,,,并且赋值成 NULL delete[] _str; _str = NULL; swap(_str,str1._str); } return *this; } ~String() { if(_str != NULL) { delete [] _str; } _str =NULL; } //重载【】 char & operator[](size_t n) { assert(n < strlen(_str) ); return *(_str+n); } protected: char *_str; }; //引用计数的浅拷贝 写实拷贝 class StringS { public: StringS(const char * str = "") { //要是传进来的字符串为 NULL if(str == NULL) { //我们需要创建一个内容为 /0的字符串 _str =new char [1]; *_str = '/0'; } else { //否则,,,开辟一个长度为 str长度+1; _str = new char [strlen(str)+1]; strcpy(_str,str); } _count = new int(1); } //拷贝构造函数 StringS(const StringS & str) :_str (str._str) ,_count(str._count) { (*_count)++; } //带有引用计数的赋值运算符的重载 StringS & operator=( const StringS & str) { if(_str != str._str) { if(*_count == 1) { delete[] _str; _str = str._str; } else { (*_count)--; _str = str._str; } _count = str._count; (*_count) ++; } return *this; } ~StringS() { if(*_count == 1) { delete[] _str; delete _count; } else { (*_count) --; } _str = NULL; _count =NULL; } //写实拷贝 //当某个对象要进行 写的话 ,,,就要对其 单独进行拷贝 char & operator[](size_t n) { assert(n < strlen(_str) ); if(*_count != 1)//如果这个数 多个 对象使用的话 { char * tmp = new char[strlen(_str)+1]; strcpy(tmp,_str); _str = tmp; (*_count)--; _count = new int(1); } return *(_str+n); } protected: char * _str; int * _count ;//表示的是 引用计数 }; void testString() { String st(NULL); String st1; String st2("we are happy"); String st3(st2); st1 = st3; } void testStringS() { StringS st(NULL); StringS st1; StringS st2("we are happy"); StringS st3(st2); st1 = st3; st2[2]; }
相关文章推荐
- 【C++】模拟String___引用计数写实拷贝
- 使用C#拷贝String到struct
- 深浅拷贝——string
- String--引用计数写时拷贝
- 扩展spring的BeanUtils,增加拷贝属性排除null值的功能(注:String为null不考虑)
- C++——string的深拷贝与浅拷贝
- 模仿实现C++库函数----String 类----用 写时拷贝 实现
- 利用string 字符串拷贝
- 浅拷贝与深拷贝并实现String
- NSString与NSMutableString的深浅拷贝
- C++的std::string的“读时也拷贝”技术
- String深拷贝
- java 数组 、 for each循环, 数组的两种拷贝方法 ,Arrays.copyOf(),Arrays.toString[],匿名数组
- C++ String写时拷贝(Copy On Write)
- 关于STL中string的拷贝问题
- C++ string 读时也可能发生拷贝
- C# j基本操作-拷贝文件夹的所有内容到另一个文件夹内: 复制代码 1 public static void CopyDir(string srcPath, string实现文件夹的复制以及删除
- String 字符串的追加,数组拷贝
- C++中string和char的区别以及直接初始化和拷贝初始化
- string的写时拷贝分析