atexit 函数
称为终止处理程序注册程序,注册完成以后,当函数终止是exit()函数, 会主动的调用前面注册的各个函数
特点
- 调用 exit 函数时,会主动调用被注册的函数,执行清理工作
- 发生在 main 函数结束之后
- 函数参数是函数的地址
- 先注册的函数后实现,类似于栈
- 只接受无返回类型,即 void 类型的函数
简单测试:
#include <bits/stdc++.h>
#define rep( i , j , n ) for ( int i = int(j) ; i < int(n) ; ++i )
#define dew( i , j , n ) for ( int i = int(n-1) ; i > int(j) ; --i )
#define display( say ) std::cout << std::endl << say << std::endl
#define _PATH __FILE__ , __LINE__
typedef std::pair < int , int > P ;
using std::cin ;
using std::cout ;
using std::endl ;
using std::string ;
class Gragh {
private:
int data ;
public:
Gragh () : data ( 0 ) {
const char* say = "我是默认构造函数" ;
display ( say ) ;
atexit ( My_test ) ;
}
explicit Gragh ( int _data ) : data ( _data ) {
const char* say = "我是构造函数" ;
display ( say ) ;
}
// error: cannot convert 'Gragh::My_test' from type 'void (Gragh::)()' to type 'void (*)()'
static void My_test () {
const char* say = "我是类的 static void 函数" ;
display ( say ) ;
}
void test_void () {
const char* say = "我是 void 的普通成员函数" ;
display ( say ) ;
}
~Gragh () {
const char* say = "我是析构函数" ;
display ( say ) ;
}
} ;
void test1 () {
const char* say = "I am test1" ;
display ( say ) ;
}
void test2 () {
const char* say = "I am test2" ;
display ( say ) ;
}
void test3 () {
const char* say = "I am test3" ;
display ( say ) ;
}
void test4 () {
const char* say = "I am test4" ;
display ( say ) ;
Gragh *One = nullptr ;
One->test_void () ;
}
bool test5 () {
const char* say = "I am test5" ;
display ( say ) ;
return true ;
}
int main () {
atexit ( test1 ) ;
atexit ( test2 ) ;
atexit ( test3 ) ;
Gragh *One = new Gragh () ;
delete One ;
atexit ( test4 ) ; // 在 main 函数之后调用
atexit ( Gragh::My_test ) ;
// atexit ( test5 ) ;
// error: invalid conversion from 'bool (*)()' to 'void (*)()' [-fpermissive]
const char* say = "我是 main 函数" ;
display ( say ) ;
return 0 ;
}
程序运行结果:
笔记
- 被注册的函数类似于入栈,先进后出。这为程序员提供了一种自主决定函数调用先后关系的手段
- 被注册的最后一个函数是 static void 函数,所以,最早调用,一般在面对对象中可以采用这种方式释放内存,或者容器清空的操作
- 支持普通 void 函数
支持对象中的 void 函数
支持类中的 static void 函数。
原因可能是, atexit 函数是在 main 函数结束之后会被 exit 触发,而 static 关键字是全局的,可见全局变量区和类,对象的的函数的生存期都比 main 的生存期更长- 在 main 函数结束之后,还可以输出语句,说明了 I/O 流的清理工作晚于 main 函数,而且晚于 atexit 函数