在涉及到类中的成员变量是指针时,这个时候如果使用浅拷贝就会非常容易出现对象指针悬置的问题,出现这种问题的原因是由于对象在局部区域使用后会依次析构,对于浅拷贝,他只是将变量内存的地址拷贝到另外一个变量,言外之意是这两个对象指向同一块空间,所以当一个对象析构时,另外一个对象再次析构时,就会出现异常,也就是浅拷贝在这里出现的问题。
解决浅拷贝思路就是使用深拷贝,经过上述分析,所谓的深拷贝,实质上就是另外开辟一块空间存储上述内容(即重新编写拷贝构造函数)
#include<iostream>
using namespace std;
#pragma warning(disable:4996) // strcpy()函数会出现异常,添加此代码
class Test {
public:
char* p;
int len;
// 构造函数
Test(const char* mp) {
len = strlen(mp);
p = (char*)malloc(len + 1); // 开辟一个空间
strcpy(p, mp);
}
// 自定义析构函数
~Test() {
if (p != NULL) {
free(p); //释放p的空间
len = 0;
}
}
};
void mainobj() {
Test t1("asdfghjk");
Test t2 = t1;
}
int main() {
mainobj();
system("pause");
}
上述代码,如果我们通过F9后分步运行后,会发现在析构t1对象时执行到析构函数时会出现异常现象,我们分析一下为什么会这样?
上述代码首先会执行带一个参数的构造函数,完成t1对象的初始化, 其次,当执行Test t2 = t1; 这句话时, 编译器没有发现拷贝构造函数,这时候系统会默认自动调用系统默认的拷贝构造函数。 问题就出现在这里,这里的系统调用的默认的拷贝构造函数是一个浅拷贝,它只是简单的将t1对象的字符串的地址与长度简单的复制给t2, 言外之意,t1与t2对象指向了同一个字符串“asdfghjk”, 所以当mainobj()函数执行完毕时,由局部对象要进行销毁,所以要调用析构函数,所以这时,t2先析构,它析构带来的结果是将字符串清楚了,等t1在次析构时,由于该字符串在t2析构后已经不存在了,所以会报异常。
上述就是浅拷贝带来的问题,浅拷贝实质上就是两个对象指向了同一块内存地址导致的,那么解决浅拷贝就是将这两个对象指向不同的内存空间。也就是不使用系统默认的拷贝构造函数,我们自己编写拷贝构造函数,我们编写新的拷贝构造函数的目的就是为了开辟一块不同的空间去存储t1,这样就解决了浅拷贝,实现深拷贝。
#include<iostream>
using namespace std;
#pragma warning(disable:4996)
class Test {
public:
char* p;
int len;
// 构造函数
Test(const char* mp) {
len = strlen(mp);
p = (char*)malloc(len + 1); // 开辟一个空间
strcpy(p, mp);
}
//针对浅拷贝存在问题,这里自定义一个拷贝构造函数解决浅拷贝问题
Test(const Test& obj) {
len = strlen(obj.p);
p = (char*)malloc(len + 1);
strcpy(p, obj.p);
}
// 自定义析构函数
~Test() {
if (p != NULL) {
free(p); //释放p的空间
len = 0;
}
}
};
void mainobj() {
Test t1("asdfghjk");
Test t2 = t1;
}
int main() {
mainobj();
system("pause");
}
将上述代码进行步进后,会发现上面的问题消失了,也就是通过深拷贝解决了浅拷贝问题。。