C++ 深拷贝、浅拷贝和拷贝构造函数

浅拷贝:浅拷贝就是指不重新申请新的内存空间,仅仅是给原来被拷贝的量取了一个别名。这两名字都是共用的同一块内存空间。最典型的就是指针变量赋值在通过一个指针修改了内存空间中的内容后,另外的指针也会发生相应改变。如下所示:

#include <iostream>
using namespace std;

void test1()
{
    int* p1 = new int(1);
    int* p2 = p1;

    cout << "*p1 = " << *p1 << endl;
    cout << "*p2 = " << *p2 << endl;

    *p2 = 2;
    cout << "after change *p2 to 2" << endl;
    cout << "*p1 = " << *p1 << endl;
    cout << "*p2 = " << *p2 << endl;    
}

int main()
{
    test1();
    return 0;
}

输出结果为:

*p1 = 1
*p2 = 1
after change *p2 to 2
*p1 = 2
*p2 = 2

深拷贝:深拷贝是指拷贝过程中重新分配了新的内存空间存放拷贝的内容,通过拷贝后的变量名对内存空间中的内容进行修改,不影响原来的内存空间。最典型的是普通变量的赋值。如下所示:

int a = 1;
int b = a;
cout << "a = " << a << endl;
cout << "b = " << b << endl;

b = 2;
cout << "after convert b to 2" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;

输出结果为:

a = 1
b = 1
after convert b to 2
a = 1
b = 2

拷贝构造函数:

前面的内容都是铺垫,有了前面的认识,再进入拷贝构造函数就很容易理解了。由上面可知,浅拷贝会带来一定的问题,就是可以通过其他的变量访问、修改、甚至删除原先的内容和内存空间。这在指针和普通变量的复制上还看不出特别大的问题,但在有构造函数和析构函数的类中,必然会有问题看下面的代码:

class Student
{
    public:
    string name;
    int *score;

    Student(){}
    Student(string name, int inputscore[])
    {
        this->score=new int[2];
        this->score[0]=inputscore[0];
        this->score[1]=inputscore[1];
    }           
    ~Student()
    {
        delete [] score;
        cout << "~Student() is called" << endl;
    }
};

void test3()
{
    int a1[2]  = {80, 90};
    Student stu1("stu1", a1);
    cout << stu1.score[0] << endl;
    cout << stu1.score[1] << endl;

}

输出结果为:

80
90
~Student() is called

这是没有问题的,下面我们再新建一个Student类的实例stu2,并用stu1给它赋值,代码如下:

int a1[2]  = {80, 90};
Student stu1("stu1", a1);
cout << stu1.score[0] << endl;
cout << stu1.score[1] << endl;

Student stu2(stu1);

输出结果为:

80
90
~Student() is called
~Student() is called

这里问题就出现了,由于c++默认的拷贝构造函数是浅拷贝,所以意味着析构函数被调用一次之后,内存已经被释放,而stu2使用完成之后自动调用了自己的析构函数,释放了同一块内存。关于释放同一块内存的造成的后果及是否报错,可以参看我之前的博文。从现在的结果看,析构函数显然被调用了两次,释放了同一块内存,是一定不能被接受的。

所以,一旦我们要使用“=”给类的实例互相赋值,那么就需要手动写自己的拷贝构造函数,将带有指针的成员变量重新申请内存空间,普通变量不用(原因看看前面的例子就知道了)。代码如下:

class Student
{
    public:
    string name;
    int *score;

    Student(){}
    Student(string name, int inputscore[])
    {
        this->score=new int[2];
        this->score[0]=inputscore[0];
        this->score[1]=inputscore[1];
    }   
    Student(const Student& stu)
    {
        score = new int[2];
        score[0] = stu.score[0];
        score[1] = stu.score[1];
    }    

    ~Student()
    {
        delete [] score;
        cout << "~Student() is called" << endl;
    }
};

int a1[2]  = {80, 90};
Student stu1("stu1", a1);
cout << stu1.score[0] << endl;
cout << stu1.score[1] << endl;

Student stu2(stu1);
stu2.score[0] = 85;
cout << stu1.score[0] << endl;
cout << stu2.score[0] << endl;

输出结果为:

80
90
80
85
~Student() is called
~Student() is called

这里虽然析构函数仍然调用了两次,但是明显释放的已经不是同一块内存了。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值