浅拷贝
举例:
class Base {};int a = 10;int b = a; // 浅拷贝Base obj1();Base obj2 = obj1; // 浅拷贝
上面例子 b 和 obj2 都是以拷贝的方式初始化,具体就是将 a 和 obj1 所在内存中的数据按照二进制位(Bit)复制到 b 和 obj2 所在的内存;
这种默认的拷贝行为就是浅拷贝,这和调用 memcpy() 函数的效果非常类似。
对于简单的类,默认的拷贝构造函数一般就够用了,我们也没有必要再显式地定义一个功能类似的拷贝构造函数。但是当类持有其它资源时,例如动态分配的内存、指向其他数据的指针等,默认的拷贝构造函数就不能拷贝这些资源了,我们必须显式地定义拷贝构造函数,以完整地拷贝对象的所有数据。
深拷贝
举例:
class Array {public:Array(const Array &arr) {this->m_len = arr.m_len;this->m_p = (int*)calloc(this->m_len, sizeof(int));memcpy(this->m_p, arr.m_p, m_len * sizeof(int));}private:int m_len;int *m_p;};
显式地定义了拷贝构造函数,它除了会将原有对象的所有成员变量拷贝给新对象,还会为新对象再分配一块内存,并将原有对象所持有的内存也拷贝过来。
参考: C++深拷贝和浅拷贝(深复制和浅复制)完全攻略 (biancheng.net)
深拷贝与浅拷贝的区别
<1> 浅拷贝动态内存会导致重复析构
当出现类的等号赋值时,会调用拷贝构造函数,在未显示定义拷贝构造函数的情况下, 系统会调用默认的拷贝构造函数-即浅拷贝,它能够完成成员的⼀⼀复制。当数据成员中没有指针时,浅拷贝是可行的。
但当数据成员中有指针时,如果采⽤简单的浅拷贝,则两类中的两个指针指向同⼀个地址,当 对象的生命周期结束时,会调用两次析构函数,而导致野指针的问题
<2> 使用深拷贝避免重复释放内存导致野指针问题
所以这个时候必须使用深拷贝. 深拷贝与浅拷贝之间的区别就在于深拷贝会在堆内存中另外申请空间来存储数据,从⽽也就解决了野指针的问题.
:::info 简而言之,当类的数据成员中有指针时,必需要用深拷贝更加安全 :::
