深拷贝浅拷贝分析:
浅拷贝:也称位拷贝,编译器只是直接将指针的值拷贝过来,结果多个对象共用同一块内存,当一个对象将这块内存释放掉之后,另一些对象不知道该块空间已经还给了系统,以为还有效,所以在对这段内存进行释放操作的时候,一个内存空间被释放多次,发生了访问违规,程序崩溃。
如图:
深拷贝:为了解决浅拷贝的问题,深拷贝则不是直接将指针的值拷贝,它是为指针p2开辟与p1相同大小的内存空间,然后将p1所指的内存str[]内容拷贝到p2自己空间中,这时由于p1、p2指向的是各自不同的内存空间,delete时只释放自己的内存,不会出现访问违规。
如图:
string类的实现则不能使用浅拷贝的方法,在这里则以深拷贝的方法模拟实现它的传统写法与现代写法简洁版:
代码如下:
#pragma once #include <string.h> //String类的实现 class String { public: //构造函数 String(const char* pStr=NULL) { if(pStr==NULL) { _pStr=new char[1]; *_pStr='\0'; } else { _pStr=new char[strlen(pStr)+1]; strcpy(_pStr,pStr);//strcpy拷贝了'\0' } } //析构函数 String() { if(_pStr!=NULL) { delete[] _pStr; _pStr=NULL; } } //拷贝构造函数 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(const String& s) :_pStr(NULL) { String temp(s._pStr);//调用构造函数 std::swap(_pStr,temp._pStr);//交换内容 } //赋值运算符重载 String& operator=(const String& s) { if(this!=&s) { String temp(s);//String temp(s._pStr)//创建临时对象 std::swap(_pStr,temp._pStr); //交换内容 }//出了作用域临时对象析构,即析构了_pStr原内容 return *this; } String& operator=(String s) //值传递:调用了一次拷贝构造函数,并不会改变s原对象内容 { std::swap(_pStr,s._pStr); //交换内容,出了函数由于为值传递s._pStr析构,即析构了_pStr原内容 return *this; }*/ private: char* _pStr; }; void Test() { String s1("hello"); String s2("world"); String s3(s1); s3=s2; }在以上实现中,1.特别注意的为赋值运算符重载的实现,当两个string对象s2、s3相互赋值时,如以上代码s3=s2,因为s3之前也有自己的内存空间,所以在赋值前,一定要释放s3原本的内存,否则会造成内存泄漏;
2.在简洁版实现中思想为:以一个临时对象内容交换现在对象内容,即实现了现有对象内容重新赋值,也使它原本内容存于临时对象中,出了函数作用域自动析构销毁。