c++类深拷贝和浅拷贝(只有在数据成员涉及到指针的时候才有差异)

本文主要介绍了C++中浅拷贝和深拷贝的概念。浅拷贝是简单复制,编译器自动生成的拷贝构造函数执行的也是浅拷贝,当对象有动态成员时会出现内存重复释放问题。深拷贝则是重新申请堆区内存再拷贝。当数据成员有指针时,需采用深拷贝来避免重复释放现象。

概述:
浅拷贝:简单生硬的复制拷贝构造操作,编译器自动生成的拷贝构造函数执行的也是浅拷贝。
深拷贝:重新向堆区申请内存空间,然后再进行拷贝操作。
大多情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员,那么浅拷贝就会出问题了,
那么会出现什么问题呢? 内存重复释放的错误。
看一段代码。(错例示范)

#include<iostream>
using namespace std;
class Rect
{
public:
    Rect()
    {
     p=new int(100);
    }
   
    ~Rect()
    {
       if(p!=NULL)
        delete p;
    }
private:
    int *p;
};
int main()
{
    Rect rect1;
    Rect rect2(rect1);
    return 0;
}

我们会发现这段代码是错误的,语法上没问题,但在实际运行中就会爆断点,原因就是我定义rect1的时候向堆区申请了一块内存来存放数据,而堆区返回一个指针并且存在p当中,到这里没什么问题,但是下面我又用rect1去拷贝出来一个rect2,这里用的是浅拷贝,就是直接把rect1中的指针复制一份给了rect2,两个指针指向同一块堆区内存,而不是rect2重新向堆区申请了一块新内存并赋上数据,到这里也还正常。但是下面我要析构了,这是rect2的析构先把p指针指向的内存清除掉,轮到rect1析构时,他要再析构一次p指向的堆区内存,但是我的内存以及被rect2析构过一次了,不能再析构了,所以这时候就会爆错。
在这里插入图片描述
为了解决这个问题,我们就需要深复制,就是拷贝的时候不复制指针,而是直接再重新申请一份堆区内存存放相同的数据,而且指针不一样。

2.下面贴一个深复制的代码(这里就涉及到指针形式的数据成员)

#include<iostream>
using namespace std;
class Rect
{
public:
//下面有语法
    Rect()
    {
        p = new int(100);
    }
    Rect(const Rect& rect) {
        p = new int(*rect.p);
    }
        ~Rect()
        {
            if (p != NULL)
                delete p;
        }
    int* p;
    };
    int main()
    {
        Rect rect1;
        Rect rect2(rect1);
        return 0;
    }

在这里插入图片描述

总结:
结:
拷贝有两种:深拷贝,浅拷贝。
当出现类的等号赋值时,会调用拷贝函数,在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。当数据成员中没有指针时,浅拷贝是可行的。但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,而导致重复释放现象。所以,这时,必须采用深拷贝。

 深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据,从而也就解决了重复释放的问题。
 简而言之,当数据成员中有指针时,必须要用深拷贝。

几个小问题:

1.为什么拷贝构造函数要设置为引用&,而不设置为值传递呢?

简单点讲就是为了防止递归调用。
详细讲就是:我们以及知道,当 一个对象需要以值方式传递时,编译器会生成代码调用它的拷贝构造函数以生成一个复本。
假如我们把类A的拷贝构造函数设置成以值方式传递一个类A对象作为参数的话,当需要调用类A的拷贝构造函数时,需要以值方式传进一个A的对象作为实参; 而以值方式传递需要调用类A的拷贝构造函数;结果就是调用类A的拷贝构造函数导致又一次调用类A的拷贝构造函数,这就是一个无限递归。

2. 以下函数哪个是拷贝构造函数,为什么?
 
X::X(const X&);   //拷贝构造函数
X::X(X); 
X::X(X&, int a=1);   //拷贝构造函数
X::X(X&, int a=1, int b=2);  //拷贝构造函数

解答:对于一个类X, 如果一个构造函数的第一个参数是下列之一:
a) X&
b) const X&
c) volatile X&
d) const volatile X&
且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ad_m1n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值