目录
在成员函数中调用delete this会出现什么问题?对象还可以使用吗?
如果在类的析构函数中调用delete this,会发生什么?
1.默认(缺省)成员函数:析构函数
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作由编译器完成
对象在销毁时会自动调用析构函数,完成对象中资源的清理工作
析构函数特性
1. 析构函数名是在类名前加上字符 ~
2. 无参数无返回值类型
3.一个类只能有一个析构函数。若未定义,系统会自动生成默认的析构函数。析构函数不能重载
4.对象生命周期结束,C++自动调用析构函数
5.手动开辟的例如Stack中malloc,fopen等需要析构函数,Date日期类不需要析构函数
6.编译器生成的默认析构函数,对内置类型不做处理,对自定类型成员调用它的析构函数
7.析构函数可以定义在类外
~Stack()
{
free(...);
}
析构函数顺序
先定义的先构造,后定义后构造; 先定义的后析构,后定义的先析构(栈和栈帧里面的对象都要符合后进先出)
class A
{
public:
A(int a = 0)
{
_a = a;
cout << "A(int a = 0)->" <<_a<< endl;
}
~A()
{
cout << "~A()->" <<_a<<endl;
}
private:
int _a;
};
void f()
{
A aa1(1);
A aa2(2);
}
int main()
{
f();
return 0;
}
当带有static时,析构和构造函数的创建/销毁顺序是?
两个局部静态对象,一个全局对象
class A
{
public:
A(int a = 0)
{
_a = a;
cout << "A(int a = 0)->" <<_a<< endl;
}
~A()
{
cout << "~A()->" <<_a<<endl;
}
private:
int _a;
};
A aa3(3);
void f()
{
static A aa4(4);
A aa1(1);
A aa2(2);
static A aa5(5);
}
int main()
{
f();
return 0;
}
全局变量最先被初始化(main函数之前初始化,全局和静态都在静态区),局部静态特点是第一次运行后初始化
析构是aa2和aa1中最先析构,原因在于剩余三个生命周期在程序结束后才销毁,main函数栈帧结束清理在栈帧中的aa2和aa1;main函数结束,再调用全局和静态(符合先定义后析构)
如果调用两次f()函数,结果又是如何?
静态变量在第一次执行后初始化,第一次函数调用结束,aa4和aa5不会销毁
在成员函数中调用delete this会出现什么问题?对象还可以使用吗?
在类对象的内存空间中,只有数据成员和虚函数表指针,并不包含代码内容,类的成员函数单独放 在代码段中。在调用成员函数时,隐含传递一个this指针,让成员函数知道当前是哪个对象在调用它。 当调用delete this时,类对象的内存空间被释放。在delete this之后进行的其他任何函数调用,只要不涉及到this指针的内容,都能够正常运行。一旦涉及到this指针,如操作数据成员,调用虚函数等,就会出现不可预期的问题。
为什么是不可预期的问题?
delete this之后不是释放了类对象的内存空间了么,那么这段内存应该已经还给系统,不再属于这个进程。照这个逻辑来看,应该发生野指针之类的令崩溃的问题。这个问题牵涉到操作系统的内存管理策略。delete this释放了类对象的内存空间,但是内存空间却并不是马上被回收到系统中,可能是缓冲或者其他什么原因,导致这段内存空间暂时并没有被系统收回。此时这段内存是可以访问的,你可以加上100,加上200,但是其中的值却是不确定的。当你获取数据成员,可能得到的是未初始化的随机数;访问虚函数表,指针无效的可能性非常高,造成系统崩溃。
如果在类的析构函数中调用delete this,会发生什么?
会导致堆栈溢出。delete的本质是“为将被释放的内存调用一个或多个析构函数,然后,释放内存”。显然,delete this会去调用本对象的析构函数,而析构函数中又调用delete this,形成无限递归,造成堆栈溢出,系统崩溃。
2.拷贝构造函数
有时候我们需要对一个对象进行拷贝,就会调用拷贝构造函数
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
int main()
{
Date d1(2022, 7, 31);
Date d2(d1);//拷贝构造两个写法
Date d3 = d1;
return 0;
}