Namespaces
Variants

std:: exit

From cppreference.net
Utilities library
定义于头文件 <cstdlib>
void exit ( int exit_code ) ;
(C++11 前)
[ [ noreturn ] ] void exit ( int exit_code ) ;
(C++11 起)

导致程序正常终止。

执行以下几个清理步骤:

1) 具有静态存储期的对象会被销毁,且通过调用 std::atexit 注册的函数会被调用:
a) 具有静态存储期的非局部对象按其构造函数完成顺序的逆序销毁。
b) 通过 std::atexit 注册的函数按其注册顺序的逆序调用,但若某函数在注册时已有先前注册的函数被调用过,则该函数会在这些函数之后调用。
c) 对于每个通过 std::atexit 注册的函数 f 及每个具有静态存储期的非局部对象 obj
  • f obj 初始化之前注册,则 f 仅在 obj 销毁之后调用;
  • f obj 初始化之后注册,则 f 仅在 obj 销毁之前调用。
d) 对于每个具有静态存储期的局部对象 obj ,其销毁过程如同在 obj 构造函数完成时,通过 std::atexit 注册了一个调用 obj 析构函数的函数。
(C++11 前)
1) 与当前线程关联的具有线程局部 存储期 的对象的析构函数、具有静态存储期的对象的析构函数,以及通过 std::atexit 注册的函数会并发执行,同时保证以下规则:
a) 线程局部对象的最后一个析构函数 先序于 静态对象的第一个析构函数。
b) 若线程局部或静态对象 A 的构造函数或 动态初始化 完成先序于线程局部或静态对象 B,则 B 的销毁完成先序于 A 的销毁开始。
c) 若静态对象 A 的初始化完成先序于对某函数 F 调用 std::atexit ,则终止过程中对 F 的调用先序于 A 的销毁开始。
d) 若对某函数 F 调用 std::atexit 先序于静态对象 A 的初始化完成,则 A 的销毁开始先序于终止过程中对 F 的调用。
e) 若对某函数 F1 调用 std::atexit 先序于对某函数 F2 调用 std::atexit ,则终止过程中对 F2 的调用先序于对 F1 的调用。
(C++11 起)
  • 在上述情况下,
  • 若任何通过 atexit 注册的函数或任何静态/线程局部对象的析构函数抛出异常,将调用 std::terminate
  • 若编译器选择将对象的动态初始化提升至 非局部初始化 的静态初始化阶段,其析构顺序仍遵循原本的动态初始化顺序。
  • 若函数局部(块作用域)静态对象已被销毁,而后在另一静态对象的析构函数中调用该函数,且控制流经过该对象的定义点(或通过指针/引用间接使用该对象),则行为未定义。
  • 若函数局部(块作用域)静态对象在类子对象或数组的构造过程中被初始化,则仅当该类的所有子对象或该数组的所有元素均被销毁后,该静态对象才会被销毁。
2) 所有C流被刷新并关闭。
3) std::tmpfile 创建的文件会被移除。
4) 控制权返回给主机环境。若 exit_code 0 EXIT_SUCCESS ,则返回表示成功终止的实现定义状态。若 exit_code EXIT_FAILURE ,则返回表示未成功终止的实现定义状态。其他情况下返回实现定义的状态值。

栈不会展开:具有自动 存储期 的变量的析构函数不会被调用。

目录

与主函数的关系

main 函数 返回时,无论是通过 return 语句还是执行到函数末尾,都会执行正常的函数终止流程(调用具有自动 存储期 的变量的析构函数),随后执行 std::exit ,并将 return 语句的参数(若使用隐式返回则为 0 )作为 exit_code 传递。

参数

exit_code - 程序的退出状态

返回值

(无)

示例

#include <cstdlib>
#include <iostream>
struct Static
{
    ~Static() 
    {
        std::cout << "Static destructor\n";
    }
};
struct Local
{
    ~Local() 
    {
        std::cout << "Local destructor\n";
    }
};
Static static_variable; // 此对象的析构函数*将*被调用
void atexit_handler()
{
    std::cout << "atexit handler\n";
}
int main()
{
    Local local_variable; // 此对象的析构函数*不会*被调用
    const int result = std::atexit(atexit_handler); // 处理函数将被调用
    if (result != 0)
    {
        std::cerr << "atexit registration failed\n";
        return EXIT_FAILURE;
    }
    std::cout << "test\n";
    std::exit(EXIT_FAILURE);
    std::cout << "this line will *not* be executed\n";
}

输出:

test
atexit handler
Static destructor

缺陷报告

下列行为变更缺陷报告被追溯应用于先前发布的C++标准。

缺陷报告 适用范围 发布时行为 正确行为
LWG 3 C++98 在清理过程中,当(1)函数通过 std::atexit 注册或(2)静态局部对象被初始化时,行为不明确 已明确说明

参见

导致程序异常终止(不进行清理操作)
(函数)
注册在调用 std::exit() 时执行的函数
(函数)
(C++11)
导致程序快速终止而不完全清理
(函数)
注册在调用 std::quick_exit 时执行的函数
(函数)
C 文档 for exit