深浅拷贝问题是面试经典问题,今天我们来全面认识一下。
C++中的构造函数有三类:默认构造函数,有参构造函数,拷贝构造函数。
前两种构造函数主要用于默认值对成员变量进行初始化或者是传递指定参数对成员变量进行出初始化,而拷贝构造函数是用一个已经定义的对象进行拷贝。
认识浅拷贝:如果类当中没有定义拷贝构造函数,则会调用默认的拷贝构造函数。默认的拷贝构造函数中会对对象中的变量进行简单的赋值拷贝操作,就是调用等号进行赋值,这就是浅拷贝。
认识深拷贝:深拷贝就是在堆区重新申请一块空间来存放自己的数据。
简单的文字解释很难对深浅拷贝有较深的理解下面那我们看两个实例。
首先是浅拷贝的实例:
这里我们可以看出来调用了两次析构函数说明b对象拷贝a对象成功,并且最后还成功释放了资源。
继续看下一个例子:
当类成员变量中含有指针或者引用,将变量定义在堆区,此时继续使用默认的拷贝构造函数对a进行拷贝是否还会像之前那样成功?
结果发现程序崩溃了。
为什么会发生崩溃,我们来分析一下,首先我们的对象a实例化时会调用含参构造函数进行初始化,初始化过程中会向堆区申请空间,并且指针变量ptr还会指向申请的空间,接着我们创建b、对象并且调用默认的拷贝构造函数对b进行初始化此时会发生下面的情况
两个指针指向同一块堆区的空间,这就会导致在调用析构函数时候会出现重复释放同一块内存空间的问题。这就是浅拷贝典型的问题。由于编译器默认的拷贝构造函数就是浅拷贝,所以我们需要重新定义拷贝构造函数。
重新申请一块堆空间存放数据。
这样就不会出现像浅拷贝那样重复释放空间的问题。
总结:浅拷贝就是编译器实现的直接等号复制操作,深拷贝重新申请一块空间,进行拷贝操作,所以如果对象中有属性在堆区中开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题。