深拷贝与浅拷贝

前面说到了拷贝构造函数,但是情况并未列举完。我怕文章太长就分开写,看的舒服。

有一种情况,那就是当构造函数中有指针操作,怎么办?

#include <iostream>
using namespace std;
class A{
private:
    int *a;
public:
    A(){
        a = new int[100];
        cout<<"构造函数"<<endl;
    }
    ~A(){
        delete a;
        cout<<"析构函数"<<endl;
    }
};
int main(){
    A a;
    A b = a;
    return 0;
}

看起来没有错,但是会在运行时报错:

深拷贝与浅拷贝

翻译一下,testSTACK是我工程的名字,被释放的指针没有被分配,也就是说析构函数释放了一个空指针!

怎么会呢?

这就涉及到一个知识点,就是堆栈关系:堆栈关系

如果嫌文章太长,那我就简单说一下。new出来的对象和指针不存放在同一片内存中,他们是指向关系。

深拷贝与浅拷贝

当我们第一次使用析构函数释放掉pointer1的时候,pointer1指向的堆空间new int[100]被释放,到这一步一切顺利。

但是这时候pointer2其实已经指空了!再对pointer2进行释放,会报错。

就像一个软件,存在路径a上,现在创建一个快捷方式,放在桌面,路径为b,当a删除,b自然找不到源文件。

简单的说,这种只拷贝了指针但是没有拷贝指针指向的地址空间的拷贝,叫做浅拷贝。

可是在一些时候,这样做会出错,我们怎么解决这样的错误?利用深拷贝。

什么是深拷贝,就是连同地址空间一起拷贝。

深拷贝与浅拷贝

这样释放的时候便不会出错。

#include <iostream>
using namespace std;
class A{
private:
    int *a;
public:
    A(){
        a = new int;
        cout<<"构造函数"<<endl;
    }
    A(const A& b){
        a = new int[100];
        *a = *(b.a);
        cout<<"拷贝构造函数"<<endl;
    }
    ~A(){
        delete a;
        cout<<"析构函数"<<endl;
    }
};
int main(){
    A a;
    A b = a;
    return 0;
}

深拷贝与浅拷贝

在执行 A b = a 的时候,编译器调用拷贝构造函数。为对象b中的私有成员a申请了一片空间之后,让指针a指向这篇空间。这片空间被赋值为与参数中的空间相同,所以不会出现浅拷贝的情况。


问:拷贝构造函数为什么需要用引用传递,而不用值传递?

答:若是值传递,那么每次声明参数的时候都会再找值赋给当前声明的参数,这样一来就会进行无限递归的死循环。而引用传递利用地址,直接确定了拷贝对象的地址,不会造成无限递归。