C++笔记-深拷贝与浅拷贝

C++笔记-深拷贝与浅拷贝

对于拷贝构造函数,需要注意的一点是要使用深拷贝,不然有可能会出现double free错误。

首先需要清楚的一点是:浅拷贝只复制某个对象的指针,但是并不会复制该对象的内容,只是新建了一个指向该内存地址的指针。而深拷贝则是将整个对象复制,双方不会共享内存。

Demo

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 Foo{
private:
int *p;
int n;
public:
Foo(int n){
this->n = n;
p = new int[n];
}

Foo(Foo &other){
this->n = other.n;
this->p = other.p;
}
void printArray(){
for(int i = 0; i < n; ++i){
cout << this->p[i] << endl;
}
}
~Foo(){
delete [] p;
}
};

int main(){
Foo obj1{3};
Foo obj2 = obj1;
return 0;
}

对于上述程序,如果我们直接运行,则会出现double free。首先我们新建了一个对象obj1,obj1初始化的时候会创建一个长度为3的动态数组p。

我们使用拷贝构造函数创造对象obj2,这个时候obj2中的p并没有进行深拷贝,而是接受了obj1中数组p的起始地址。

当程序执行结束,obj1首先被析构函数销毁,此时p区域已经被释放,而obj2再次被销毁时就会重复释放已经空的地址,从而导致double free。

Solution

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
34
35
36
37
#include<iostream>

using namespace std;

class Foo{
private:
int *p;
int n;
public:
Foo(int n){
this->n = n;
p = new int[n];
}

Foo(Foo &other){
this->n = other.n;
// this->p = other.p;
this->p = new int[other.n];
for(int i = 0; i < other.n; i++){
this->p[i] = other.p[i];
}
}
void printArray(){
for(int i = 0; i < n; ++i){
cout << this->p[i] << endl;
}
}
~Foo(){
delete [] p;
}
};

int main(){
Foo obj1{2};
Foo obj2 = obj1;
return 0;
}

拷贝数组p时使用深拷贝,申请完内存再将数组内的所有元素复制进来。