1、拷贝函数从结构体的赋值说起
struct Person {
char * name;
int age;
};
int main () {
struct Person p1 = Person{"张三",24};
struct Person p2 =p1;
cout << "p1:"<< &p1 << " p2"<<&p2 <<endl;
return 0 ;
}
在以上代码中,p2的地址和p1的地址是不同的,和我们讲的int赋值是一样的,结构体的赋值也是这样的。 struct Person p2 =p1; 这句话是把 p1 所有的成员复制一份赋给 p2。
2、既然有默认的拷贝函数,我们为什么要实现自定义的拷贝函数?什么是浅拷贝?浅拷贝会引发什么问题?
说这个问题,就要从内存地址说起。搞明白在拷贝构造函数里内存地址的变化,就能明白浅拷贝和深拷贝的原理。下面看一段代码
class Student {
private:
int age;
char* name;
public:
//无参构造
Student() {
cout << "空参数构造函数" << endl;
}
//一个参数的构造方法
Student(char* name):Student(name,99) {
cout << "一个参数的构造函数 this" <<this << endl;
}
//两个参数的构造函数
Student(char* name, int age) {
cout << "两个参数的构造函数 this" << this << endl;
this->name = (char*)malloc(sizeof(char*) * 10);
strcpy(this->name, name);
this->age = age;
}
//析构函数
~Student(){
cout << "析构函数 this->name" << this->name << endl;
free(this->name);
this->name = NULL;
}
void print() {
cout << "print this->name:" << static_cast<const void*> (this->name) << " name的值:" << this->name << endl;
}
};
int main() {
char* name = (char *)"好好好";
Student stu1(name);
Student stu2 = stu1;//执行拷贝函数
stu1.print();
stu2.print();
return 0;
}
先说结论,运行这段代码会报错,原因是因为在Student stu2 = stu1;的时候执行了拷贝函数,而默认的拷贝函数执行的是浅拷贝,在给stu2这个成员赋值的时候, 由于 char * 是一个指针变量,所以stu2的 name的值,和stu1的name的值是一样的,所以在析构函数里进行free回收的时候,同一个地址会回收两次,导致程序报错。 这就是浅拷贝。浅拷贝只拷贝了数据的地址。 这里需要画一张图来理解。
所以为了避免这种情况,我们就需要自定义拷贝构造函数。类成员是指针类型变量时,就自己开辟一块空间,把原先的值复制一份放进来。这就是深拷贝。
3、C++中的拷贝构造函数
拷贝函数和空参函数一样,不写都有默认函数,如果自己写了就会覆盖默认的拷贝函数。和Java的空参构造一个道理。
浅拷贝
//拷贝函数
Student::Student(const Student & student) {//常量引用,只读的,不让你改。
this->name =student->name;
this->age = student->age -10;//进行减龄操作
}
深拷贝
Student(const Student & student) {
//深拷贝
this->name = (char *) malloc(sizeof(char) * 10);
strcpy(this->name, student.name);
this->age = student.age;
cout << "拷贝构造函数 &student " << &student << "this " << this << endl;
}
我们再拷贝指针变量类型的数据时,为新构建的对象的成员变量,开辟一块新的空间,再把旧对象的值,复制一份到新空间,这样,我们在回收的时候,就不会冲突了,自己的空间,就可以自己玩了,你再释放就和旧对象没有半毛钱关系了。
4、总结
在C++中,我们书写的成员有指针变量时,比如 char* 和Student * 在传参或者赋值时,构造函数只拷贝了其地址,没有拷贝其内容的情况,我们称之为浅拷贝。会引发同一地址多次释放的错误。我们要真正拷贝内容时,必须需要一个新空间,新地址。来放拷贝过来的内容。这种情况称之为深拷贝。