目录
前言
01 什么是析构函数
1.1 举个栗子
02 为什么要写析构函数
前言
今天我们要讨论一下它的“孪生兄弟”,析构函数,它们在某些方面非常相似。
与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统会自动执行析构函数。以C++语言为例:析构函数名也应与类名相同,只是在函数名前面加一个位取反符~,例如~stud( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数(即使自定义了析构函数,编译器也总是会为我们合成一个析构函数,并且如果自定义了析构函数,编译器在执行时会先调用自定义的析构函数再调用合成的析构函数),它也不进行任何操作。所以许多简单的类中没有用显式的析构函数。
01 什么是析构函数
C++ 中的析构函数是一种特殊的成员函数,用于在对象的生命周期结束时执行清理操作。当对象的作用域结束、被 delete 或者程序结束时,都会自动调用其析构函数。
析构函数的作用是释放对象所占用的资源,例如动态分配的内存、打开的文件句柄、网络连接等。在析构函数中,可以编写必要的清理代码,确保对象所使用的资源得到正确的释放,从而避免资源泄漏和内存泄漏等问题。
当一个 C++ 对象不再被使用时,其所占用的内存需要被释放以免造成内存泄漏,析构函数就是用来释放对象所占用的内存的特殊成员函数。
1.1 举个栗子
让我们深入看一些例子。
我们直接使用构造函数那一期中使用的代码。
P16 C++构造函数-CSDN博客
(上一章的代码)
#include <iostream>class Log
{
public:int maxSize; int minSize;public:Log(int max,int min) {maxSize = max;minSize = min;}void print(){std::cout << maxSize << std::endl;std::cout << minSize << std::endl;}
};int main()
{Log log(10,6);log.print();return 0;
}
在这个例子中我们创建了 Log类,这里还有一个带参数的构造函数。
让我们再添加一个析构函数。
你可以看到,构造函数和析构函数在声明与定义时的唯一区别就是放在析构函数前面的波浪号。有了这个符号,你就知道这是析构函数了。
在这个例子中,我们只有一个简单的类,有两个成员maxSize、minSize。当我们为这两个整形变量申请内存的时候,完全没有考虑之后怎么清除内存。在之后的系列中我们会继续讨论内存分配等所有这些复杂的问题。
我们添加一条打印消息,用于告诉我们对象已经被删除。在构造函数中,我也添加了一条信息。删除第二个构造函数,这样我们就不会搞混了。
为了看到这个过程,我要写一个函数 testLog,它将执行 Log的相关操作。
运行代码之后,我们可以看到下面的结果,构造函数和析构函数都执行了
让我们更深入的看看它是如何工作的。
设置断点来调试一下,如果不知道如何设置断点debug调试的话,可以看我主页的博文
你会看到 Log的实例 log 被创建出来,也会打印created Log,最后作用域结束了,黄色箭头跳出函数的作用域,析构函数就被执行了,打印出delete Log。
因为它的对象是在栈上创建的,当超出作用域时,它会被自动销毁。你可以看到当函数执行完成的时候,会输出删除 log的信息,因为析构函数被调用了。
这就是析构函数的本质。
它只是一个特殊函数或特殊方法,在对象被销毁时被调用。
02 为什么要写析构函数
那么我们为什么要写析构函数呢?
因为如果在构造函数中调用了特定的初始化代码,你可能想要在析构函数中卸载或销毁所有这些东西。因为如果你不这样做,可能会造成内存泄露。
一个很好的例子是在堆上分配的对象。如果你已经在堆上手动分配了任何类型的内存,那么你需要手动清理。
如果在 Log类使用中或构造中分配了内存,你可能会要在析构函数中删除它们,因为当析构函数调用时,那个 Log实例对象会消失。
最后附上本章使用过的代码
#include <iostream>class Log
{
public:int maxSize; int minSize;public:Log(int max,int min) {maxSize = max;minSize = min;std::cout << "created Log" << std::endl;}~Log(){std::cout << "delete Log" << std::endl;}void print(){std::cout << maxSize << std::endl;std::cout << minSize << std::endl;}
};void testLog()
{Log log(10,6);log.print();
}int main()
{testLog();return 0;
}