Visual Studio 编译环境验证:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdio.h>
using namespace std;
#define LOG(format, ...) printf(format, ##__VA_ARGS__)
class Student
{
public:
int age;
char * name;
Student(){
LOG("空参数构造函数\n");
}
Student(char * name) :Student(name, 99){
cout << "一个参数构造函数 this:" << (int)this << endl;
}
Student(char * name, int age){
cout << "二个参数构造函数 this:" << (int)this << endl;
this->name = (char *)malloc(sizeof(char*)* 10);
strcpy(this->name, name);
this->age = age;
}
~Student(){
cout << "析构函数执行 &this->name:" << (int)this->name << endl;
free(this->name);
this->name = NULL;
}
Student(const Student &stu){
cout << "拷贝构造函数 &stu:" << (int)&stu << " this:" << (int)this << endl;
//浅拷贝;相当于复制内存的内容,但是始终指向同一块内存空间
//this->name = stu.name;
//深拷贝:创建新的地址
this->name = (char*)malloc(sizeof(char*)* 10);
strcpy(this->name,stu.name);
this->age = stu.age;
cout << "拷贝构造函数 stu.name:" << (int)stu.name << " this->name:" << (int)this->name << endl; //验证为什么崩溃
}
};
void showStudent(Student stu){
cout << "showStudent函数:" << (int)&stu << " " << stu.name << "," << stu.age << endl;
}//出栈 就会执行析构函数 做释放内存操作
void main(){
Student stu("张三",11);
showStudent(stu);
//结果打印:
//二个参数构造函数 this:13892916 ——————> Student stu("张三",11);
//拷贝构造函数 &stu : 13892916 this : 13892680 --------->showStudent(Student stu)执行的时候会将上一步 创建的stu通过拷贝构造函数重新申请一个新的stu地址
//showStudent函数:13892680 张三, 11 -------> showStudent 拿到了新地址的stu
//析构函数执行 &this->name : 14401392
showStudent(stu); // 再调用showStudent函数 也会奔溃
getchar();//去掉此行 程序运行奔溃
//拷贝构造函数添加打印 新旧stu地址对应的name地址,打印结果:
//二个参数构造函数 this:15727400
//拷贝构造函数 &stu : 15727400 this : 15727164
//拷贝构造函数 &stu : 19382768 this->name : 19382768 // 新旧stu对象的name指向的地址是相同的
//showStudent函数:15727164 张三, 11
//析构函数执行 &this->name : 19382768
//多次条用showStudent 或者取掉 getchar奔溃原因:
//多次调用showStudent当第一个showStudent出栈会执行析构函数释放name内存 第二个showStudent出栈时也会调用析构函数释放内存
//去掉getchar main 函数出栈 释放旧地址stu的name 内存 新旧stu对象的name地址相同 情况同上 也是做了多次释放操作
//****************************************************************************************************
//添加深拷贝后调用两次showStudent打印如下:
//二个参数构造函数 this:10025748
//拷贝构造函数 &stu : 10025748 this : 10025500
//拷贝构造函数 stu.name : 1229304 this->name : 1229408 //新旧stu对应的栈空间name的内存地址是不一样的
//showStudent函数:10025500 张三, 11
//析构函数执行 &this->name : 1229408
//拷贝构造函数 &stu : 10025748 this : 10025500
//拷贝构造函数 stu.name : 1229304 this->name : 1229408 //释放后重新指向的地址和上一次相同 无关紧要,因为上有个showStudent已经出栈了
//showStudent函数:10025500 张三, 11
//析构函数执行 &this->name : 1229408 //多次释放没有任何影响
}//出栈 旧的stu地址做释放操作
请参考以上代码做测试。
补充一点:默认的拷贝构造函数是浅拷贝
验证方法:把重写的拷贝构造函数注释掉,打开多次调用showStudent此时运行会崩溃
所以:如果成员中都堆成员,则必须使用深拷贝