2024-07-13 07:00:00

如何结束c++代码

我想我的c++代码停止运行,如果某个条件得到满足,但我不知道如何做到这一点。因此,在任何时候,如果if语句为真,就像这样终止代码:

if (x==1)
{
    kill code;
}

调用std::exit函数。


要么从main返回一个值,要么使用exit函数。两者都采用int型。返回什么值并不重要,除非有一个外部进程监视返回值。


通常,您将使用具有适当退出状态的exit()方法。

零意味着成功运行。非零状态表示发生了某种问题。父进程(例如shell脚本)使用此退出码来确定进程是否成功运行。


当执行流到达主函数的末尾时,程序将终止。

要在此之前终止它,可以使用exit(int status)函数,其中status是返回到启动程序的值。0通常表示非错误状态


正如Martin York提到的,退出不像返回那样执行必要的清理。

在exit的地方使用return总是更好。 如果你不在主程序中,无论你想退出程序的哪个位置,请先返回主程序。

考虑下面的例子。 使用下面的程序,将用所提到的内容创建一个文件。 但是如果return是带注释的&未注释的exit(0),编译器不会保证文件将有所需的文本。

int main()
{
    ofstream os("out.txt");
    os << "Hello, Can you see me!\n";
    return(0);
    //exit(0);
}

不仅如此,在程序中有多个退出点会使调试更加困难。 仅在可以对其进行合理解释时使用exit。


如果在代码深处的某个地方出现错误,那么要么抛出异常,要么设置错误代码。抛出异常总是比设置错误代码更好。


人们常说“调用退出(返回代码)”,但这是不好的形式。在小程序中是可以的,但是有一些问题:

您最终将从程序中获得多个退出点 它使代码更加复杂(比如使用goto) 它不能释放在运行时分配的内存

实际上,你唯一应该退出这个问题的时候是main.cpp中的这一行:

return 0;

如果您正在使用exit()来处理错误,那么您应该了解异常(以及嵌套异常),这是一种更加优雅和安全的方法。


超出调用exit(error_code)——调用退出处理程序,但不调用RAII析构函数等。 -我越来越多地使用异常。

我的主程序越来越像

int main(int argc, char** argv) 
{
    try {
        exit( secondary_main(argc, argv );
    }
    catch(...) {
        // optionally, print something like "unexpected or unknown exception caught by main"
        exit(1);
    }
}

在secondary_main 所有原本放东西的地方 例如,原来的main被重命名为secondary_main,上面的存根main被添加。 这只是一个细节,这样在main中的tray和catch之间就不会有太多的代码。

如果需要,可以捕获其他异常类型。 我很喜欢捕捉字符串错误类型,比如std::string或char*,然后打印出来 在main中的catch处理程序中。

使用这样的异常至少允许调用RAII析构函数,这样它们就可以进行清理。这可能是愉快和有用的。

总的来说,C错误处理-退出和信号-和c++错误处理-尝试/捕获/抛出异常-在最好的情况下不一致地一起发挥作用。

然后,检测到错误

throw "error message"

或者一些更特定的异常类型。


有几种方法,但首先你需要理解为什么对象清理是重要的,以及为什么std::exit在c++程序员中被边缘化。

RAII和Stack Unwinding

c++使用了一种称为RAII的习惯用法,简单来说,这意味着对象应该在构造函数中执行初始化,在析构函数中执行清理。例如std::ofstream类[可以]在构造函数期间打开文件,然后用户对其执行输出操作,最后在其生命周期的末尾(通常由其作用域决定)调用析构函数,本质上关闭文件并将所有写入的内容刷新到磁盘。

如果没有使用析构函数刷新并关闭文件,会发生什么?谁知道!但它可能不会将应该写入文件的所有数据写入文件。

例如,考虑下面的代码

#include <fstream>
#include <exception>
#include <memory>

void inner_mad()
{
    throw std::exception();
}

void mad()
{
    auto ptr = std::make_unique<int>();
    inner_mad();
}

int main()
{
    std::ofstream os("file.txt");
    os << "Content!!!";

    int possibility = /* either 1, 2, 3 or 4 */;
    
    if(possibility == 1)
        return 0;
    else if(possibility == 2)
        throw std::exception();
    else if(possibility == 3)
        mad();
    else if(possibility == 4)
        exit(0);
}

每种可能性发生的情况是:

Possibility 1: Return essentially leaves the current function scope, so it knows about the end of the life cycle of os thus calling its destructor and doing proper cleanup by closing and flushing the file to disk. Possibility 2: Throwing a exception also takes care of the life cycle of the objects in the current scope, thus doing proper cleanup... Possibility 3: Here stack unwinding enters in action! Even though the exception is thrown at inner_mad, the unwinder will go though the stack of mad and main to perform proper cleanup, all the objects are going to be destructed properly, including ptr and os. Possibility 4: Well, here? exit is a C function and it's not aware nor compatible with the C++ idioms. It does not perform cleanup on your objects, including os in the very same scope. So your file won't be closed properly and for this reason the content might never get written into it! Other Possibilities: It'll just leave main scope, by performing a implicit return 0 and thus having the same effect as possibility 1, i.e. proper cleanup.

但不要太确定我刚刚告诉你的(主要是可能性2和3);继续阅读,我们将了解如何执行适当的基于异常的清理。

可能的结束方式

从主舱回来!

只要有可能,你就应该这样做;总是倾向于通过从main中返回适当的退出状态来从程序返回。

程序的调用者(可能还有操作系统)可能想知道程序应该做的事情是否成功完成。出于同样的原因,你应该返回0或EXIT_SUCCESS来表示程序成功终止,EXIT_FAILURE来表示程序不成功终止,任何其他形式的返回值都是由实现定义的(§18.5/8)。

然而,你可能在调用堆栈中非常深,返回所有的可能是痛苦的…

[不]抛出异常

抛出异常将通过调用任何先前作用域中每个对象的析构函数,使用堆栈展开执行适当的对象清理。

但这里有个问题!当抛出的异常没有被处理(通过catch(…)子句),或者即使在调用堆栈中间有noexcept函数时,是否执行堆栈展开,这是由实现定义的。如§15.5.1[除。terminate外]所述:

In some situations exception handling must be abandoned for less subtle error handling techniques. [Note: These situations are: [...] — when the exception handling mechanism cannot find a handler for a thrown exception (15.3), or when the search for a handler (15.3) encounters the outermost block of a function with a noexcept-specification that does not allow the exception (15.4), or [...] [...] In such cases, std::terminate() is called (18.8.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called [...]

所以我们必须抓住它!

请抛出异常并在main捕获它!

由于未捕获的异常可能不会执行堆栈展开(因此不会执行适当的清理),我们应该在main中捕获异常,然后返回退出状态(EXIT_SUCCESS或EXIT_FAILURE)。

所以一个好的设置应该是:

int main()
{
    /* ... */
    try
    {
        // Insert code that will return by throwing a exception.
    }
    catch(const std::exception&)  // Consider using a custom exception type for intentional
    {                             // throws. A good idea might be a `return_exception`.
        return EXIT_FAILURE;
    }
    /* ... */
}

[不要]std::exit

这不会执行任何类型的堆栈展开,堆栈上的活动对象也不会调用其各自的析构函数来执行清理。

在§3.6.1/4 [basic.start.init]中强制执行:

在不离开当前块的情况下终止程序(例如,通过调用std::exit(int)函数(18.5))不会破坏任何具有自动存储持续时间的对象(12.4)。如果std::exit被调用来结束一个程序,在一个对象的静态或线程存储持续时间的销毁过程中,该程序具有未定义的行为。

现在想想,你为什么要做这样的事?你痛苦地损坏过多少物品?

其他(糟糕的)选择

还有其他方法可以终止程序(而不是崩溃),但不推荐使用。为了澄清起见,它们将在这里呈现。请注意,正常的程序终止并不意味着堆栈展开,而是操作系统的正常状态。

std::_Exit causes a normal program termination, and that's it. std::quick_exit causes a normal program termination and calls std::at_quick_exit handlers, no other cleanup is performed. std::exit causes a normal program termination and then calls std::atexit handlers. Other sorts of cleanups are performed such as calling static objects destructors. std::abort causes an abnormal program termination, no cleanup is performed. This should be called if the program terminated in a really, really unexpected way. It'll do nothing but signal the OS about the abnormal termination. Some systems perform a core dump in this case. std::terminate calls the std::terminate_handler which calls std::abort by default.


返回0;把它放在int main()中任何你想要的位置,程序将立即关闭。


伙计……Exit()函数定义在stdlib.h下

所以你需要添加一个预处理器。

将include stdlib.h放在头部分

然后使用exit();任何你喜欢的地方,但记得在退出的括号里放一个整数。

例如:

exit(0);

如果我正在测试的情况确实是坏消息,我会这样做:

*(int*) NULL= 0;

这给了我一个很好的coredump,从那里我可以检查情况。


如果你的If语句在循环中,你可以使用

 break; 

如果你想转义一些代码并继续循环使用:

继续;

如果你的If语句不在循环中,你可以使用:

 return 0;

Or 




  exit();

打破一个条件使用return(0);

所以,在你的情况下,它将是:

    if(x==1)
    {
        return 0;
    }