什么是深拷贝?
深拷贝不同于浅拷贝,它在拷贝的时候会为新对象开辟一块新的内存空间,然后将原对象的内容拷贝到新开辟的空间,这样在资源释放的时候就不会牵扯到多次析构·的问题。比如构造了S1与S2两个对象,在构造S2时拷贝一块跟S1指向数据库一样大的数据块,并将值拷贝下来,这样S1与S2指向各自的数据块,析构时也自然释放自己的数据块。
- 源代码及注释(简洁版)
#include <iostream>
#include <Windows.h>
using namespace std;
class String
{
public:
//构造函数
String(const char* pStr = "")
:_pStr(new char[strlen(pStr) + 1])
{
if(*_pStr == NULL)
*_pStr = '\0';
else
strcpy(_pStr,pStr);
}
//拷贝构造函数
String(String& s)
:_pStr(NULL)//初始化_pStr
//防止交换后pTemp指向随机空间
{
String pTemp(s._pStr);//给出临时空间,交换后s不为NULL
std::swap(_pStr,pTemp._pStr);
}
//析构函数
~String()
{
if(NULL == _pStr)
{
return;
}
delete[] _pStr;
_pStr = NULL;
}
// 赋值运算符=号的重载
String& operator=(const String& s)
{
if(_pStr != s._pStr)
{
String pTemp(s._pStr);//给出临时空间,交换后s不为NULL
std::swap(_pStr,pTemp._pStr);
}
return *this;
}
private:
char *_pStr;
};
void FunTest()
{
String s1("Hello world");
String s2(s1);
String s3 = s2;
}
int main()
{
FunTest();
system("pause");
return 0;
}
深拷贝的内存分析
①调用构造函数创建S1、S2、S3后,发现3个对象的地址完全不同,证明处于不同的内存空间中。
②调用三次析构函数,发现在释放的过程中遵循先入后出的原则,没有发生任何的内存泄漏或者程序奔溃问题。
普通版本的深拷贝
对于拷贝构造函数:开辟新空间,在进行内容的拷贝使其各有各自的空间以至于在析构的时候不至于程序运行崩溃。比如创建了S1、S2两个对象,构造S2对象时拷贝一块跟S1指向数据块一样大的数据块,并将值拷贝下来,这样S1、S2指向各自的数据块,析构时释放各自的数据块,因此就不会出现浅拷贝空间被多次析构的错误。但是美中不如是,虽然深拷贝看起来较为容易的解决了字符串的拷贝,但是新开辟的空间无疑成为了资源的浪费。
- String.h
#include <iostream>
#include <Windows.h>
#include <string.h>
#pragma warning (disable:4996)
using namespace std;
class String
{
public:
String(const char *pStr = "")
{
if(pStr == NULL)
{
_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()
{
if(_pStr)
{
delete[] _pStr;
_pStr = NULL;
}
}
size_t Size()const;//字符串的大小
size_t Lengh()const;//字符串的长度
char& operator[](const size_t index);//下标界定符
const char& operator[](size_t index)const;
bool operator>(const String& s);
bool operator<(const String& s);
bool operator==(const String& s);
bool operator!=(const String& s);
void Copy(const String& s);
String operator+(const String& s);
bool strstr(const String& s);
String& operator=(const String& s);
String& operator+=(const String& s);
friend ostream& operator<<(ostream& _cout,const String& s);
private:
char *_pStr;
};
//main.cpp
#include "String.h"
void FunTest()
{
String s1("Hello world");
String s2(s1);
String s3 = s1 + s2;
cout<<"s1 = "<<s1<<endl;
cout<<"s2 = "<<s2<<endl;
cout<<"s3 = "<<s3<<endl;
}
int main()
{
FunTest();
system("pause");
return 0;
}
//String.cpp
#include "String.h"
size_t String::Size()const
{
size_t count = 0;
char *p = _pStr;
while(*p != '\0')
{
++count;
p++;
}
return count;
}
size_t String::Lengh()const
{
size_t count;
char *p = _pStr;
while(*p != '\0')
{
++count;
p++;
}
return count;
}
char& String::operator[](size_t t)
{
if(t >= 0 && t <= strlen(_pStr))
return _pStr[t];
}
const char& String::operator[](size_t t)const
{
return _pStr[t];
}
bool String::operator>(const String& s)
{
char *pTemp1 = _pStr;
char *pTemp2 = s._pStr;
while(*pTemp1 == *pTemp2)
{
pTemp1++;
pTemp2++;
}
if(*pTemp1 > *pTemp2)
return true;
else
return false;
}
bool String::operator<(const String& s)
{
char *pTemp1 = _pStr;
char *pTemp2 = s._pStr;
while (*pTemp1 == *pTemp2)
{
pTemp1++;
pTemp2++;
if(*pTemp1 < *pTemp2)
return true;
else
return false;
}
return false;
}
bool String::operator==(const String& s)
{
int ret = strcmp(_pStr,s._pStr);
if(0 == ret)
return true;
return false;
}
bool String::operator!=(const String& s)
{
return !(*this == s);
}
bool String::strstr(const String& s)
{
char* pTemp1 = _pStr;
char* pTemp2 = s._pStr;
char pTemp = NULL;
while(*pTemp1 != '\0' && *pTemp2 != '\0')
{
while(*pTemp1 == *pTemp2)
{
pTemp1++;
pTemp2++;
}
pTemp1++;
}
if(*pTemp2 == '\0')
return true;
else
return false;
}
String& String::operator=(const String& s)
{
if(this != &s)
{
delete[] _pStr;
_pStr = new char[strlen(s._pStr) + 1];
strcpy(_pStr,s._pStr);
}
return *this;
}
ostream& operator<<(ostream& _cout,const String& s)
{
_cout<<s._pStr;
return _cout;
}
String String::operator+(const String& s)
{
String s1;
if (!s._pStr)
s1 = *this;
else if (!_pStr)
s1 = s;
else {
s1._pStr = new char[strlen(_pStr) + strlen(s._pStr) + 1];
strcpy(s1._pStr, _pStr);
strcat(s1._pStr, s._pStr);
}
return s1;
}
String& String::operator+=(const String& s)
{
char *Temp1 = (*this)._pStr;
char *Temp2 = s._pStr;
int len1 = strlen(Temp1);
int len2 = strlen(Temp2);
char *Buff = NULL;
char *end = NULL;
Buff = new char[len1 + len2 + 1];
strcpy(Buff, Temp1);
end = Buff + len1;
strcpy(end, Temp2);
delete[]_pStr;
_pStr = Buff;
return (*this);
}
void String::Copy(const String& s)
{
int idx = 0;
char *pTemp1 = new char[strlen(s._pStr) + 1];
char *pTemp2 = s._pStr;
for (idx = 0; pTemp2[idx] != '\0'; idx++)
{
pTemp1[idx] = pTemp2[idx];
}
pTemp1[idx] = '\0';
delete[]_pStr;
_pStr = pTemp1;
}