1.浅拷贝
概念:浅拷贝也叫位拷贝,即在拷贝发生时,编译器只是将对象中的值按照基本的数据类型复制过来。例如以下就是个简单的复制过程:
int a = 10;
int b = a;
将a的值赋给b的过程就是一个浅拷贝过程,这不会有任何问题。但是如果一个类中包含有指针成员变量,采用浅拷贝则会引发一些问题。例如以下:
#include <iostream>
#include <string>
using namespace std;
class String
{
public:
String(const char *str)
{
cout << "string()" << endl;
if (str == NULL)
{
str = new char[1];
}
else
{
mstr = new char[strlen(str) + 1];
memcpy(mstr, str, strlen(str) + 1);
}
}
~String()
{
cout << "~string()" << endl;
if (mstr)
{
delete[] mstr;
}
}
private:
char* mstr;
};
int main()
{
String str1("hello");//调用构造函数
String str2(str1);//调用默认拷贝构造函数
return 0;
}
运行代码,结果如下:
同样,该程序也会崩溃。为何程序会崩溃呢?是因为该类没有显示定义拷贝构造函数,所以在执行str2(str1)的时候会调用默认的拷贝构造函数,而默认的拷贝构造函数就是采用浅拷贝来完成对象的复制的。所以在完成拷贝后,str1和str2中的两个指针成员变量就会指向同一个地址,即“hello”。在程序结束时,两个类对象都会调用析构函数,这样就导致了同一个地址空间被delete了两次。delete同一个空间多次,在c++中是未定义的行为,会造成程序崩溃。浅拷贝后内存布局类似于下图所示:
2.浅拷贝造成的问题
造成内存泄漏,程序崩溃的问题只是浅拷贝的成果之一。
其二,由于浅拷贝造成两个指针指向同一个地址空间,所以只要其中一个修改了地址空间中的值,另一方也会受到影响。
其三,如果某一个对象先调用了析构函数,而另一个对象在对指针成员指向的空间进行访问就会报错。
3.深拷贝
深拷贝是什么?深拷贝是指对象在复制的过程中连同其所持有的资源一并拷贝的过程。如此一来,就能避免浅拷贝所带来的的程序崩溃问题。为了实现深拷贝,我们往往需要自己定义并实现拷贝构造函数,而不是使用编译器生成的拷贝构造函数。
#include <iostream>
#include <string>
using namespace std;
class String
{
public:
String(const char *str)
{
cout << "string()" << endl;
if (str == NULL)
{
str = new char[1];
}
else
{
mstr = new char[strlen(str) + 1];
memcpy(mstr, str, strlen(str) + 1);
}
}
//自定义拷贝构造函数
String(const String& s)
{
cout << "copy string" << endl;
mstr = new char[strlen(s.mstr) + 1];//从堆区分配内存空间
memcpy(mstr, s.mstr, strlen(s.mstr) + 1);
}
~String()
{
cout << "~string()" << endl;
if (mstr)
{
delete[] mstr;
}
}
private:
char* mstr;
};
int main()
{
String str1("hello");
String str2(str1);
return 0;
}
执行结果如下:
调用了两次构造函数,第一次调用了构造函数,第二次调用了自定义的拷贝构造函数,并且实现了深拷贝,这样就不会有程序崩溃的问题。
对于上述的自定义拷贝构造函数,还有另外一种写法。
String(const String& s)
{
cout << "copy string" << endl;
String s1(s.mstr);
swap(mstr,s.mstr);
}
String s1(s.,mstr)这一句这是利用了构造函数去开辟了一段空间,并复制指针所指向的地址空间的值,然后再通过swap的函数交换两个空间即可。
4.总结
浅拷贝对于指针而言只是拷贝了指针的值,经过浅拷贝的两个指针将会指向同一个地址,但是深拷贝
不仅拷贝指针,而且还会将指针指向的值进行拷贝,这样两个指针指向的是两个不同的地址,只不过两个地址存放的内容是完全一样的。