浅拷贝
思想:我们用指针p申请了一块内存空间,在用指针q指向了这一片内存空间,这时候这两个指针指向的是同一个内存空间,当需要释放这块内存空间的时候p会释放一次,q也会释放一次,这样重复释放就会引发程序的崩溃。
我们通过一段代码来理解浅拷贝
class Person
{
public:
char* name;
int age;
~Person()
{
if (name != NULL)
{
free(name);
name = NULL;
}
}
};
void Test()
{
Person p1;
p1.name = (char *)malloc(1000);
strcpy(p1.name, "nihao");
p1.age = 20;
Person p2 = p1;
}
int main()
{
Test();
return 0;
}
这一段代码的看起来没事,编译器也不会报错,但是当你执行的时候程序会崩溃,这一段代码就是因为浅拷贝而出现奔溃的。这段代码只有在实例化p1的时候去申请了1000个字节空间,然后给p1的name和age实例化,代码到这里没有任何问题;在往下走,用p1来拷贝构造p2,但是p2没有申请内存空间,只是将p2的name的指针指向了p1的那段内存空间,这段也没有错;问题出在调用析构函数的时候,因为p1的name和p2的那么的内存空间指向了同一片内存空间,所以p1释放的时候不会出错,但是p2也会释放自己的内存空间,这就会重复的释放,大家都知道,多次释放同一片内存空间程序会崩溃,这就是问题所在了。要想解决这个问题,那么我们就用到了深拷贝。
深拷贝
思想:我们用对象p申请一块内存空间,然后我们用对象p来构造我们的对象q,这个时候我们需要给对象q也申请一块内存空间,然后将p对象里里面的值拷贝到对象q中,在释放他们的时候各自释放的都是各自的空间,这样程序也就不会像浅拷贝一样发生崩溃了。
下面我们看一下深拷贝的代码
class Person
{
public:
char* name;
int age;
Person()
{
}
Person(const Person& per)
{
int len = strlen(per.name) + 1;
name = (char *)malloc(len);
strcpy(name, per.name);
}
~Person()
{
if (name != NULL)
{
free(name);
name = NULL;
}
}
};
int main()
{
Person p1;
p1.name = (char *)malloc(1000);
strcpy(p1.name, "nihao");
p1.age = 20;
Person p2 = p1;
return 0;
}
写时拷贝
当需要实例化大量对象的时候,如果你每一个都执行深拷贝,这样就程序一直开辟的内存空间,会造成大量的空间浪费,所以我们就用到了写时拷贝,当你需要对用到的对象进程操作的时候,对该对象开辟内存空间,进行深拷贝,会节省很多的空间。