在了解深拷贝以及写时拷贝之前,我们先来了解什么是浅拷贝,看下面代码:
class String
{
public:
String(char* ptr = "")
:_ptr(new char[strlen(ptr)+1])
{
if (_ptr != NULL)//空间开辟成功
{
strcpy(_ptr, ptr);
}
}
String(const String& s)
:_ptr(s._ptr)//直接赋值
{}
String& operator= (const String& s)
{
if (this != &s)
{
delete[] _ptr;
_ptr = s._ptr;//直接赋值
}
return *this;
}
~String()
{
if (_ptr)
{
delete[]_ptr;
}
}
private:
char* _ptr;
};
如下:s1、s2、s3是String类的三个对象,执行下列代码,目的是让s1、s2、s3在各自的内存空间内存放着字符串”sulijuan“,但却事与愿违。
String s1("sulijuan");
String s2(s1);
String s3;
s3 = s1;
可以通过调试看到最后s1、s2、s3都指向了同一块空间:
执行过程如下:
那么可想而知,最后释放对象的时候,理应调用三次析构函数来释放三个对象,s3最先被释放,当s3被释放了以后,同时把s1、s2指向的空间一起释放了,当再次调用析构函数想释放s2时,程序崩溃了
~因为s2对象的_ptr指针指向的空间已经还给了操作系统,试图去释放一个不属于你的空间必然崩溃~~~~~~~~
.为了解决浅拷贝的问题,引入了深拷贝。。。。。。。。
浅拷贝是多个对象指向了同一块空间,导致最后释放空间出现了问题;那么深拷贝俗一点讲就是让每个对象对应一块空间,各自管各自的空间,互不影响,最后释放各自的空间。
代码如下:
class String
{
public:
String(char* ptr = "") //构造函数
:_ptr(new char[strlen(ptr)+1])
{
if (_ptr)
{
strcpy(_ptr, ptr);
}
}
String(const String& s)
:_ptr(new char[strlen(s._ptr)+1])//另外开辟空间
{
strcpy(_ptr, s._ptr);
}
String& operator= (const String& s)
{
if (this != &s)
{
delete[] _ptr;
_ptr = new char[strlen(s._ptr) + 1];//另外开辟空间
strcpy(_ptr, s._ptr);
}
return *this;
}
~String()
{
if (_ptr)
{
delete[] _ptr;
}
}
private:
char* _ptr;
};
再次执行下面代码:
String s1("sulijuan");
String s2(s1);
String s3;
s3 = s1;
调试后可知各自开辟了一块空间:
模拟库内string类的一些字符串基本操作实现如下:
#define EXPLAND_CAPICITY 5
class String
{
public:
String() //无参构造函数
:_size(0)
, _capicity(EXPLAND_CAPICITY)
, _str(new char[EXPLAND_CAPICITY])
{
*_str = '\0';
}
String(char* str) //构造函数重载
:_size(strlen(str)) //根据声明先后顺序进行初始化
, _capicity(_size+1)
, _str(new char[_capicity])
{
strcpy(_str,str);
}
String(const String& s) //深拷贝函数
:_size(s._size)
, _capicity(s._capicity)
, _str(new char[strlen(s._str)+1])
{
strcpy(_str,s._str);
}
~String() //析构函数
{
if (_str)
{
delete[] _str;
}
}
String& operator=(const String& s) //赋值运算符重载
{
if (this != &s)
{
delete[] _str;
_str = new char[strlen(s._str)+1];
strcpy(_str,s._str);
_size = s._size;
_capicity = s._capicity;
}
return *this;
}
void _CheckCapicity(int sCapicity)
{
if (_capicity - (_size + 1) < sCapicity)//检查当前容量是否足以容下将要插入字符串的长度
{
char* tmp = new char[_capicity + sCapicity];
_capicity += sCapicity;
strcpy(tmp, _str); //_size没变
delete[] _str; //将原来空间释放掉
_str = tmp; //_str指向新开辟的空间
}
}
void PushBack(char str)//尾插一个字符
{
_CheckCapicity(EXPLAND_CAPICITY);//如果当前所剩余的容量小于5,则每次增加容量5,否则不增加
_str[_size++] = str; //将本来的'\0'改掉了
_str[_size] = '\0'; //新的结尾
}
void PushBack(char* str)//尾插字符串
{
assert(str);
char* ptr = str;
int strLen = strlen(str);
_CheckCapicity(strLen);
while (strLen--)
{
_str[_size++] = *ptr++;
}
_str[_size] = '\0';
}
void PopBack() //尾删字符
{
if (_size > 0)
{
_str[--_size] = '\0';
}
}
void Insert(int index,char str) //在下标为index处插入一个字符
{
assert(index < _size);
_CheckCapicity(EXPLAND_CAPICITY);
int i = _size;
for (; i>=index; --i)
{
_str[i+1] = _str[i];
}
_str[index] = str;
_size++;
}
void Insert(int index,char* str) 在下标为index后面插入字符串
{
assert(index < _size);
int strLen = strlen(str);
_CheckCapicity(strLen);
int i = _size;
for (; i > index; i--)
{
_str[i + strLen] = _str[i]; //把一个字符一次性挪到位
}
int j = index+1;
char* ptr = str;
while (strLen--)
{
_str[j++] = *ptr++; //循环一个一个插入字符
_size++;
}
}
int Find(char str)//查找一个字符
{
int i = 0;
for (; i < _size; i++)
{
if (_str[i] == str)
{
return i;
}
}
return -1;
}
int Find(char* str)//查找字串
{
assert(str);
int len = strlen(str);
int i, j, k;
for (i = 0; i < _size; i++)
{
k = i;
for (j = 0; j < len; j++,k++)
{
if (_str[k] != str[j])
{
break;
}
}
if (str[j] == '\0')
{
return i;
}
}
return -1;
}
/关系运算符重载函数
bool operator== (const String& s)
{
char* ptr1 = _str;
char* ptr2 = s._str;
while (*ptr1 == *ptr2)
{
if (*ptr1 == '\0')
{
return true;
}
ptr1++;
ptr2++;
}
return false;
}
bool operator!= (const String& s)
{
return !(*this == s);
}
bool operator> (const String& s)
{
char* ptr1 = _str;
char* ptr2 = s._str;
while (*ptr1 == *ptr2)
{
if (*ptr1 == '\0')
{
return false;
}
ptr1++;
ptr2++;
}
if (*ptr1 > *ptr2)
{
return true;
}
else
{
return false;
}
}
bool operator>= (const String& s)
{
return (*this > s) || (*this == s);
}
bool operator< (const String& s)
{
return !(*this >= s);
}
bool operator<= (const String& s)
{
return !(*this > s);
}
//算术运算符重载函数
String operator+ (const String& s)
{
String tmp(*this);
tmp.PushBack(s._str);
return tmp;
}
String& operator += (const String& s)
{
*this = *this + s;
return *this;
}
friend ostream& operator<< (ostream& os, const String& s);//输出<<运算符重载
private:
int _size; //字符个数
int _capicity; //字符串容量
char* _str; //指向字符串
};
ostream& operator<< (ostream& os,const String& s)
{
os << s._str<<endl;
return os;
}