深拷贝和浅拷贝

  • 浅拷贝:简单的赋值拷贝操作
  • 深拷贝:在堆区重新申请空间,进行拷贝操作
  • 如果属性是在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题。

示例:在类中成员属性定义一个指针成员(下面程序中的 int* m_height; ),在有参构造函数中,利用new在堆区开辟一个空间,让该指针指向这个内存,完成赋值。若用户自己不定义拷贝赋构造函数,使用编译器定义的浅拷贝函数会出现重复释放内存空间的问题。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<iostream>
using namespace std;
class Person {
public:
Person() {
cout << "Person 的默认构造函数调用。" << endl;
}
Person(int a,int height) {
age = a;
m_height = new int(height);//堆区开辟空间
cout << "Person 的有参构造函数调用。" << endl;
}
~Person() {
//析构代码,将堆区开辟的数据做释放操作
if (m_height != NULL) {
delete m_height;
m_height = NULL;//避免野指针
}
cout << "Person 的析构函数调用。" << endl;
}
int age;
int* m_height;
};
void test01() {
Person p1(19,160);
cout << "p1的年龄" << p1.age <<" 身高为:"<< *p1.m_height << endl;
Person p2(p1); //编译器定义了一个浅拷贝函数
cout << "p2的年龄" << p2.age << " 身高为:" << *p2.m_height << endl;
}
int main() {
test01();
return 0;
}

注解:根据栈先入后出的规则,先析构P2,此时地址为0x0011所指向的内存已经释放,然后析构P1的时候便引发堆区的内存重复释放。

解决方法:深拷贝

示例:用户定义自己的深拷贝构造函数,也就是利用new 重新开辟一个新的空间

1
2
3
4
5
6
7
//自己实现拷贝构造函数 解决浅拷贝的问题
Person(const Person& p) {
cout << "Person的拷贝构造函数的调用" << endl;
age = p.age;
//m_height = p.m_height;//编译器默认实现是这行代码
m_height = new int(*p.m_height);//深拷贝,在堆区重新开辟内存
}

注解:拷贝时指向了另外一个内存,便不会出现重复释放内存的问题了