浅析深拷贝和浅拷贝

本文详细介绍了深拷贝和浅拷贝的概念,通过实例展示了两者在处理包含指针成员变量的类对象时的区别。浅拷贝仅复制指针,导致两个对象共享同一内存空间,而深拷贝则为新对象开辟独立内存,确保修改不会相互影响。未定义拷贝构造函数的类可能会导致内存问题,如内存泄漏和野指针。在类B中,自定义的深拷贝构造函数避免了这些问题,确保了对象的独立性。
摘要由CSDN通过智能技术生成

浅拷贝和深拷贝

拷贝即赋值,把一个对象拷贝给另一个对象,即是用一个对象的值赋值给另一个对象。对于普通的值拷贝,其实并没有深拷贝和浅拷贝的区别(或者可以把这类的拷贝都认为是深拷贝):

int a, b;
a = 21;
b = a;

对于深拷贝和浅拷贝,最直接的理解就是看有没有 对需要被赋值的对象开辟属于自己的内存空间 。为什么这么说呢?因为浅拷贝只是增加了一个指向原有的内存的指针,并将这个指针赋值给新对象,这种情况下,当原对象的指针对所指向内存空间的值做修改时,新对象中指针所指向的值也会被修改。而深拷贝则会为新对象开辟一个属于自己的内存空间,并会把原对象中的值通通复制一份存入这个新开辟的内存空间中,并将指向这个新的内存空间的指针返回给新对象。

对于拥有指针成员变量的类,类对象之间的拷贝不能使用浅拷贝的方式。先来看一下以下代码:

class A//未定义拷贝构造函数的类,编译器会隐式生成一个按位拷贝的拷贝构造函数
{
    public:
    int *ptr;
    A(){ ptr = new int(0); }
    ~A()
    {
        delete ptr;
        ptr = nullptr;
    }
};

class B//自定义一个深拷贝构造函数
{
    public:
    int *ptr;
    B(){ ptr = new int(0); }
    B(B& b){
        ptr = new int(*b.ptr);//为新对象申请一个新的内存空间并用对象b的值对其初始化
    }
    ~B()
    {
        delete ptr;
        ptr = nullptr;
    }
};
int main()
{
    A a;
    A aa(a);
    cout<< *a.ptr <<'\n';  //输出0
    cout<< *aa.ptr <<'\n'; //输出0
    *a.ptr = 21;
    cout<< *a.ptr <<'\n';  //输出21
    cout<< *aa.ptr <<'\n'; //输出21
    
    B b;
    B bb(b);
    cout<< *b.ptr <<'\n';  //输出0
    cout<< *bb.ptr <<'\n'; //输出0
    *b.ptr = 21;
    cout<< *b.ptr <<'\n';  //输出21
    cout<< *bb.ptr <<'\n'; //输出0
    return 0;
}//aa析构异常

在类A中,并没有声明拷贝构造函数,这样编译器会在编译的时候自动生成一个缺省的拷贝构造函数,这个函数的作用就是执行类似memcpy的按位拷贝,这是一种浅拷贝的方式,这种方式就导致了a.ptr和aa.ptr指向了同一块内存,通过a.ptr修改了内存中的值之后,对象aa也可以感受到这次修改。在main作用域结束之后,对象aa先调用了析构函数,将aa.ptr指向的内存空间释放,此时a.ptr就会成为一个野指针,之后对象a再调用析构函数是,就会执行一个 对野指针进行内存释放的操作,这是非常危险的! 而在类B中,由于声明了一个深拷贝构造函数,因此每个对象的指针成员都有一块只属于自己的内存空间,因此就不会引发内存泄漏和内存崩溃等相关问题的出现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值