C++的浅拷贝出现的错误

时间:2021-08-08 21:59:46

之前看一些资料提到浅拷贝的问题,即在复制对象时,只是对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。如果对象中存在动态成员,如指针,那么仅仅做浅拷贝是不够的,并且容易引发错误,最经典的例子:

#include <iostream>
#include <stdio.h>

using namespace std;

class A{
public:
A(){m_p = new int(10);};
~A(){cout << "destruction function" << endl;delete m_p;};
int* m_p;
};

void copyTest(A atmp){
;
}

int main(){
A a;
copyTest(a);
}

执行这段代码会出现崩溃,因为析构函数里的delete m_p执行了两次,而m_p指向的是同一块内存。因为在调用copyTest时传入了对象a,atmp利用a作为参数执行了默认拷贝构造函数,但是只是简单地把对象a的m_p的内存地址拷贝给atmp的m_p,因此这个时候atmp.m_p只是指向了和a.m_p相同的内存块。
当copyTest执行完毕后,临时变量atmp会被销毁,这个时候析构函数被调用,delete了m_p指向的内存。而当main函数执行完毕后,a对象也需要被销毁,这个时候析构函数再次被执行,而这个时候m_p已经不知道指向什么地方了,delete操作引发程序崩溃。

解决这个问题的方法有很多:一种方法是实现智能指针,对m_p进行引用计数,当引用值为0时才执行delete;也可以每次把m_p的初始值设为NULL,每次执行delete操作前先检查m_p是否为NULL,delete后再让m_p指向NULL,这个方法其实道理和智能指针差不多,只是智能指针更合理有效地利用类进行管理;还有一种做法是重写拷贝构造函数,确保在对象复制时进行深拷贝,即重新分配内存空间,并且把a中m_p指向内存的内容拷贝到分配的空间。

以上这种情况只有在利用“值传递”复制对象时才发生,如果我们传递的是指针,就不会有这种情况了:

#include <iostream>
#include <stdio.h>

using namespace std;

class A{
public:
A(){m_p = new int(10);};
~A(){cout << "destruction function" << endl;delete m_p;};
int* m_p;
};

void copyTest(A* atmp){
;
}

int main(){
A* a;
copyTest(a);
}

因为传递到copyTest的参数只是一个地址,指向的还是对象a,并没有发生对象的复制,当然就不存在上面的深浅拷贝问题了。