今天,我们来实现一个字符串String的拷贝(String用来管理字符串)~具体以浅拷贝和深拷贝的形式给出~
那么问题来了?什么是浅拷贝呢?深拷贝又是什么呢?
浅拷贝就相当于你喜欢一个人的感觉,而深拷贝相当于你爱一个人的感觉
我们都知道say like很容易,因为可能是他/她的外表所吸引,但是,say love却很难,因为你只有深入了解了他的本质才会爱上他~
浅拷贝:也称为位拷贝,编译器只是将指针的内容拷贝过来,导致多个对象共用一块内存空间,当其中任意对象将这块空间释放之后,其他对象再对这块空间进行操作时,就会导致程序崩溃。
深拷贝:为了解决浅拷贝留下来的问题,采用给每个对象各自一块空间,各吃各加饭,从实质上解决问题。
那么你是想只保持在喜欢阶段呢,还是想进一步发展呢 ε=ε=ε=(~ ̄▽ ̄)~
我们直接抛代码~
“喜欢”之浅拷贝
#include<iostream>
#include<string.h>
#include<windows.h>
using namespace std;
class String
{
public:
String(const char* pStr = "")//构造函数
{
if (NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
}
//拷贝构造函数
String(const String& s)
:_pStr(s._pStr)
{}
~String()
{
if (_pStr)
{
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
};
void FunTest()
{
String s1("hello world");
String s2(s1);
String s3;
s3 = s2;
}
int main()
{
FunTest();
system("pause");
return 0;
}
可以看到,s2虽然赋值成功了,但程序却崩溃了,这是为什么呢???
经过调试发现,程序在拷贝构造s2时,程序并未出现异常,但在对象析构时,在析构完s2之后,程序在析构s1时崩了,这是什么原因呢??
我们来分析一下代码~
由于s1和s2同时指向了同一块空间,程序在析构时,先析构了s2,空间释放,s1变为野指针,再析构s1时,那块空间已经不存在了,导致程序失败~
“爱”之深拷贝(各自拥有各自的空间)——普通版
class String
{
public:
String(const char* pStr="")
{
if (NULL == pStr)
{
_pStr = new char[1];
_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
}
String(const String& s)
:_pStr(new char[strlen(s._pStr)+1])
{
strcpy(_pStr, s._pStr);
}
//存在问题
String& operator=(const String& s)
{
if (this != &s)
{
char* Temp = new char[strlen(s._pStr) + 1];
//Temp在栈上,函数结束便会释放,开辟的空间就不存在
strcpy(Temp, s._pStr);
delete[] _pStr;
}
return *this;
}
~String()
{
if (_pStr)
{
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
};
void FunTest()
{
String s1("hello");
String s2(s1);
String s3;
s3 = s2;
}
int main()
{
FunTest();
system("pause");
return 0;
}
“深爱”之深拷贝的简洁版
class String
{
public:
String(const char* pStr = "")
{
if (NULL == pStr)
{
_pStr = new char[1];
_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
}
//有问题
//String(const String& s)
//{
// String temp(s._pStr);//调用构造函数
// swap(_pStr, temp._pStr);//把当前对象*this和临时对象temp交换
// //但是当前对象是一个野指针
//}
//解决方法一(存在问题 有可能导致申请空间失败)
//String(const String& s)
//{
// _pStr = new char[1];//创建当前空间,里面放‘\0’
// String temp(s._pStr);
// swap(_pStr, temp._pStr);
//}
//解决方法二
String(const String& s)
:_pStr(NULL)
{
String temp(s._pStr);
swap(_pStr, temp._pStr);
}
//赋值运算符重载(一)建议写这种
//String& operator=(const String& s)//传参过程中无需创建临时对象
//{
// if (this != &s)//判断如果不是自己给自己赋值才创建临时对象
// {
// String temp(s); // 调用拷贝构造函数
// swap(_pStr, temp._pStr);
// }
// return *this;
//}
//赋值运算符重载(二)不建议写这种
//String& operator=(const String& s)
//{
// String temp(s._pStr);//调用构造函数创建临时的
// swap(_pStr, temp._pStr);
// return *this;
//}
//赋值运算符重载(三)这种方式虽然也可以,但是函数在传参的过程中就构造临时对象,调用拷贝构造函数,
String& operator=(String s)//以值传递形式传递
{
swap(_pStr, s._pStr);
return *this;
}
~String()
{
if (_pStr)
{
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
};
void FunTest()
{
String s1("hello");
String s2(s1);
String s3;
s3 = s2;
}
int main()
{
FunTest();
system("pause");
return 0;
}
我想写代码同恋爱一样,如果“爱”,请“深爱”~
代码有问题或者表述有误,希望大家多多指教:)
国庆快乐~