深拷贝浅拷贝分析:
浅拷贝:也称位拷贝,编译器只是直接将指针的值拷贝过来,结果多个对象共用同一块内存,当一个对象将这块内存释放掉之后,另一些对象不知道该块空间已经还给了系统,以为还有效,所以在对这段内存进行释放操作的时候,一个内存空间被释放多次,发生了访问违规,程序崩溃。
如图:
深拷贝:为了解决浅拷贝的问题,深拷贝则不是直接将指针的值拷贝,它是为指针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.在简洁版实现中思想为:以一个临时对象内容交换现在对象内容,即实现了现有对象内容重新赋值,也使它原本内容存于临时对象中,出了函数作用域自动析构销毁。