深浅拷贝
编译器默认提供的拷贝是浅拷贝,将一个对象中所有成员变量的值拷贝到另一个对象。
然而,如果某个对象成员是指针类型,只会拷贝指针中存储的地址值,并不会拷贝指针指向的内存空间。
当通过构造函数赋值时,类外部指针和类内部指针指向同一块内存空间,会相互干扰。
class Student {
private:
char* m_name;
int m_age;
public:
Student(char* name, int age):m_name(name),m_age(age){}
void output() {
cout << m_name << " " << m_age << endl;
}
void changeName() {
m_name[0] = 'x';
}
};
int main() {
char name[10] = "blackcat";
Student* stu1 = new Student(name, 10);
stu1->output();
cout << name << endl;
stu1->changeName();
stu1->output();
cout << name << endl;
return 0;
}
不仅两个指针可以相互修改内存数据,栈空间数据很可能会释放,导致堆空间指向数据消失。
解决方案
在堆空间再开辟一块内存,把栈空间数据拷贝过来,防止相互干扰。
Student(char* name, int age){
m_name = new char[strlen(name) + 1]();
strcpy(m_name, name);
m_age = age;
}
~Student() {
if (m_name == NULL) return;
delete[] m_name;
m_name = NULL;
}
拷贝构造问题
在堆空间备份栈空间数据,可以起到指针变量赋值时进行数据隔离。
然而,如果遇到拷贝构造会出现什么问题呢?
如果成员变量是指针类型,拷贝构造会导致多个对象保存同一个指针,不同对象的指针指向同一块内存空间,因此可以相互修改,并且析构时,会对同一块内存空间进行多次析构,使得程序发生异常。
析构释放时会出现 double free 情况。
深拷贝
将原指针指向的内存空间拷贝一份到新的空间。
private:
char* m_name;
int m_age;
void copyName(const char* name) {
if (name == NULL) return;
m_name = new char[strlen(name) + 1]();
strcpy(m_name, name);
}
public:
Student(const char* name, int age) {
copyName(name);
m_age = age;
}
Student(const Student& stu) {
copyName(stu.m_name);
m_age = stu.m_age;
}