C++ 程序终止

在 C++ 中,可以通过以下方式退出程序:

  • 调用 exit 函数。
  • 调用 abort 函数。
  • main 执行 return 语句。

exit 函数

<stdlib.h> 中声明的 exit 函数将终止 C++ 程序。 作为 exit 的自变量提供的值将作为程序的返回代码或退出代码返回到操作系统。 按照约定,返回代码为零表示该程序已成功完成。 可以使用同样在 <stdlib.h> 中定义的常量 EXIT_FAILUREEXIT_SUCCESS 来指示程序是成功还是失败。

abort 函数

同样在标准包含文件 <stdlib.h> 中声明的 abort 函数用于终止 C++ 程序。 exitabort 之间的差异在于,exit 允许执行 C++ 运行时终止处理(调用全局对象析构函数)。 abort 可立即终止程序。 abort 函数绕过初始化的全局静态对象的一般析构过程。 它还绕过使用 atexit 函数指定的任何特殊处理。

Microsoft 专用:出于 Windows 兼容性原因,abort 的 Microsoft 实现可能允许 DLL 终止代码在某些情况下运行。 有关详细信息,请参阅 abort

atexit 函数

使用 atexit 函数指定在程序终止之前执行的操作。 在执行退出处理函数之前,不会销毁在调用 atexit 之前初始化的任何全局静态对象。

main 中的 return 语句

使用 return 语句可以从 main 指定一个返回值。 mainreturn 语句的行为首先类似于任何其他 return 语句。 任何自动变量都将被销毁。 然后,main 以返回值作为参数调用 exit。 请考虑以下示例:

// return_statement.cpp
#include <stdlib.h>
struct S 
{
    int value;
};
int main()
{
    S s{ 3 };

    exit( 3 );
    // or
    return 3;
}

前面示例中的 exitreturn 语句具有类似的行为。 两者都会终止程序并向操作系统返回值 3。 不同之处在于,exit 不会销毁自动变量 s,而 return 语句会销毁。

通常,C++ 需要具有 void 之外的返回类型的函数返回一个值。 main 函数是一个异常;它可以在没有 return 语句的情况下结束。 在这种情况下,它会将特定于实现的值返回到调用过程。 (默认情况下,MSVC 返回 0。)

线程和静态对象的销毁

直接调用 exit 时(或在 mainreturn 语句之后调用它时),将销毁与当前线程关联的线程对象。 然后,按与初始化相反的顺序销毁静态对象(在调用指定给 atexit 的函数(如果有)之后)。 以下示例演示如何进行此类初始化和清理工作。

示例

在下面的示例中,在进入 main 之前,将创建和初始化静态对象 sd1sd2。 使用 return 语句终止此程序后,首先销毁 sd2,然后销毁 sd1ShowData 类的析构函数将关闭与这些静态对象关联的文件。

// using_exit_or_return1.cpp
#include <stdio.h>
class ShowData {
public:
   // Constructor opens a file.
   ShowData( const char *szDev ) {
   errno_t err;
      err = fopen_s(&OutputDev, szDev, "w" );
   }

   // Destructor closes the file.
   ~ShowData() { fclose( OutputDev ); }

   // Disp function shows a string on the output device.
   void Disp( char *szData ) {
      fputs( szData, OutputDev );
   }
private:
   FILE *OutputDev;
};

//  Define a static object of type ShowData. The output device
//   selected is "CON" -- the standard output device.
ShowData sd1 = "CON";

//  Define another static object of type ShowData. The output
//   is directed to a file called "HELLO.DAT"
ShowData sd2 = "hello.dat";

int main() {
   sd1.Disp( "hello to default device\n" );
   sd2.Disp( "hello to file hello.dat\n" );
}

另一种编写此代码的方式为,使用块范围声明 ShowData 对象,这将在它们超出范围时时将其隐式销毁:

int main() {
   ShowData sd1( "CON" ), sd2( "hello.dat" );

   sd1.Disp( "hello to default device\n" );
   sd2.Disp( "hello to file hello.dat\n" );
}

另请参阅

main 函数和命令行参数