如何结束 C++ 代码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30250934/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to end C++ code
提问by The Nightman
I would like my C++ code to stop running if a certain condition is met, but I'm not sure how to do that. So just at any point if an if
statement is true terminate the code like this:
如果满足某个条件,我希望我的 C++ 代码停止运行,但我不知道该怎么做。所以在任何时候,如果一个if
语句为真,就会像这样终止代码:
if (x==1)
{
kill code;
}
回答by Denilson Amorim
There are several ways, but first you need to understand why object cleanup is important, and hence the reason std::exit
is marginalized among C++ programmers.
有几种方法,但首先您需要了解为什么对象清理很重要,因此该原因std::exit
在 C++ 程序员中被边缘化。
RAII and Stack Unwinding
RAII 和堆栈展开
C++ makes use of a idiom called RAII, which in simple terms means objects should perform initialization in the constructor and cleanup in the destructor. For instance the std::ofstream
class [may] open the file during the constructor, then the user performs output operations on it, and finally at the end of its life cycle, usually determined by its scope, the destructor is called that essentially closes the file and flushes any written content into the disk.
C++ 使用了一个叫做RAII的习语,简单来说,它意味着对象应该在构造函数中执行初始化并在析构函数中执行清理。例如std::ofstream
类[可能]在构造函数期间打开文件,然后用户对其执行输出操作,最后在其生命周期结束时,通常由其作用域决定,析构函数被调用,实质上关闭文件并刷新任何写入磁盘的内容。
What happens if you don't get to the destructor to flush and close the file? Who knows!But possibly it won't write all the data it was supposed to write into the file.
如果您没有使用析构函数来刷新和关闭文件,会发生什么?谁知道!但它可能不会将它应该写入文件的所有数据写入文件。
For instance consider this code
例如考虑这个代码
#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);
}
What happens in each possibility is:
在每种可能性中发生的情况是:
- 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 ofmad
andmain
to perform proper cleanup, all the objects are going to be destructed properly, includingptr
andos
. - Possibility 4:Well, here?
exit
is a C function and it's not aware nor compatible with the C++ idioms. It does notperform cleanup on your objects, includingos
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.
- 可能性 1:Return 本质上离开当前函数范围,因此它知道生命周期的结束,
os
因此调用其析构函数并通过关闭文件并将其刷新到磁盘来进行适当的清理。 - 可能性 2:抛出异常也会照顾当前范围内对象的生命周期,从而进行适当的清理......
- 可能性 3:这里堆栈展开开始起作用了!即使在 处抛出异常
inner_mad
,展开器也会遍历 的堆栈mad
并main
执行适当的清理,所有对象都将被正确销毁,包括ptr
和os
。 - 可能性4:嗯,在这里?
exit
是一个 C 函数,它不知道也不兼容 C++ 习惯用法。它不会对您的对象执行清理,包括os
在完全相同的范围内。因此,您的文件将无法正确关闭,因此内容可能永远不会写入其中! - 其他可能性:它只会离开主要范围,通过执行隐式
return 0
并因此具有与可能性 1 相同的效果,即适当的清理。
But don't be so certain about what I just told you (mainly possibilities 2 and 3); continue reading and we'll find out how to perform a proper exception based cleanup.
但是不要对我刚刚告诉你的事情那么确定(主要是可能性 2 和 3);继续阅读,我们将了解如何执行适当的基于异常的清理。
Possible Ways To End
结束的可能方式
Return from main!
从主返回!
You should do this whenever possible; always prefer to return from your program by returning a proper exit status from main.
你应该尽可能这样做;总是更喜欢通过从 main 返回正确的退出状态来从你的程序返回。
The caller of your program, and possibly the operating system, might want to know whether what your program was supposed to do was done successfully or not. For this same reason you should return either zero or EXIT_SUCCESS
to signal that the program successfully terminated and EXIT_FAILURE
to signal the program terminated unsuccessfully, any other form of return value is implementation-defined (§18.5/8).
你的程序的调用者,可能还有操作系统,可能想知道你的程序应该做的事情是否成功完成。出于同样的原因,您应该返回零或EXIT_SUCCESS
表示程序成功终止并表示程序未成功终止EXIT_FAILURE
,任何其他形式的返回值都是实现定义的(第18.5/8 节)。
However you may be very deep in the call stack, and returning all of it may be painful...
但是,您可能在调用堆栈中非常深入,并且返回所有调用堆栈可能会很痛苦......
[Do not] throw a exception
【不要】抛出异常
Throwing a exception will perform proper object cleanup using stack unwinding, by calling the destructor of every object in any previous scope.
通过调用任何先前作用域中每个对象的析构函数,抛出异常将使用堆栈展开来执行适当的对象清理。
But here's the catch! It's implementation-defined whether stack unwinding is performed when a thrown exception is not handled (by the catch(...) clause)or even if you have a noexcept
function in the middle of the call stack. This is stated in §15.5.1 [except.terminate]:
但这里的渔获!当抛出的异常没有被处理(通过 catch(...) 子句)或者即使你noexcept
在调用堆栈的中间有一个函数时,是否执行堆栈展开是由实现定义的。这在§15.5.1 [except.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
-specificationthat 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[...]
在某些情况下,必须放弃异常处理,以获得不太微妙的错误处理技术。[注:这些情况是:
[...]
— 当异常处理机制找不到抛出异常的处理程序时 (15.3),或者当搜索处理程序 (15.3) 遇到具有
noexcept
不允许异常的- 规范的函数的最外层块(15.4) 时,或[...][...]
在这种情况下,调用 std::terminate() (18.8.3)。在找不到匹配处理程序的情况下,在调用 std::terminate() 之前堆栈是否展开由实现定义[...]
So we have to catch it!
所以我们必须抓住它!
Do throw a exception and catch it at main!
抛出异常并在 main 处捕获它!
Since uncaught exceptions may not perform stack unwinding (and consequently won't perform proper cleanup), we should catch the exception in main and then return a exit status (EXIT_SUCCESS
or EXIT_FAILURE
).
由于未捕获的异常可能不会执行堆栈展开(因此不会执行适当的清理),我们应该在 main 中捕获异常,然后返回退出状态(EXIT_SUCCESS
或EXIT_FAILURE
)。
So a possibly good setup would be:
所以一个可能好的设置是:
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;
}
/* ... */
}
[Do not] std::exit
[不要] std::exit
This does not perform any sort of stack unwinding, and no alive object on the stack will call its respective destructor to perform cleanup.
这不会执行任何类型的堆栈展开,堆栈上的任何活动对象都不会调用其各自的析构函数来执行清理。
This is enforced in §3.6.1/4 [basic.start.init]:
这在§3.6.1/4 [basic.start.init] 中强制执行:
Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (18.5)) does not destroy any objects with automatic storage duration (12.4). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior.
在不离开当前块的情况下终止程序(例如,通过调用函数 std::exit(int) (18.5))不会破坏任何具有自动存储持续时间 (12.4) 的对象。如果在销毁具有静态或线程存储持续时间的对象期间调用 std::exit 以结束程序,则程序具有未定义的行为。
Think about it now, why would you do such a thing? How many objects have you painfully damaged?
现在想想,你为什么要做这样的事情?你痛苦地损坏了多少物品?
Other [as bad] alternatives
其他 [坏] 替代品
There are other ways to terminate a program (other than crashing), but they aren't recommended. Just for the sake of clarification they are going to be presented here. Notice how normal program terminationdoes notmean stack unwinding but an okaystate for the operating system.
还有其他方法可以终止程序(除了崩溃),但不推荐使用它们。只是为了澄清起见,它们将在此处呈现。请注意,正常的程序终止并不意味着堆栈展开,而是操作系统的正常状态。
std::_Exit
causes a normal program termination, and that's it.std::quick_exit
causes a normal program termination and callsstd::at_quick_exit
handlers, no other cleanup is performed.std::exit
causes a normal program termination and then callsstd::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 thestd::terminate_handler
which callsstd::abort
by default.
std::_Exit
导致正常的程序终止,仅此而已。std::quick_exit
导致正常的程序终止并调用std::at_quick_exit
处理程序,不执行其他清理。std::exit
导致正常的程序终止,然后调用std::atexit
处理程序。执行其他类型的清理,例如调用静态对象析构函数。std::abort
导致程序异常终止,不执行清理。如果程序以一种非常非常意外的方式终止,则应该调用它。它只会向操作系统发出有关异常终止的信号。在这种情况下,某些系统会执行核心转储。std::terminate
默认调用std::terminate_handler
which 调用std::abort
。
回答by Narendra N
As Martin York mentioned, exit doesn't perform necessary clean-up like return does.
正如 Martin York 所提到的, exit 不像 return 那样执行必要的清理。
It's always better to use return in the place of exit. In case if you are not in main, wherever you would like to exit the program, return to main first.
在退出的地方使用 return 总是更好。如果您不在 main 中,无论您想从哪里退出程序,请先返回 main。
Consider the below example. With the following program, a file will be created with the content mentioned. But if return is commented & uncommented exit(0), the compiler doesn't assure you that the file will have the required text.
考虑下面的例子。使用以下程序,将创建一个包含上述内容的文件。但是,如果 return 被注释且未注释 exit(0),则编译器不会向您保证该文件将具有所需的文本。
int main()
{
ofstream os("out.txt");
os << "Hello, Can you see me!\n";
return(0);
//exit(0);
}
Not just this, Having multiple exit points in a program will make debugging harder. Use exit only when it can be justified.
不仅如此,程序中有多个退出点会使调试更加困难。仅在可以证明其合理性时才使用 exit。
回答by jkeys
People are saying "call exit(return code)," but this is bad form. In small programs it is fine, but there are a number of issues with this:
人们说“调用退出(返回代码)”,但这是不好的形式。在小程序中,这很好,但是有很多问题:
- You will end up having multiple exit points from the program
- It makes code more convoluted (like using goto)
- It cannot release memory allocated at runtime
- 您最终会从程序中获得多个退出点
- 它使代码更加复杂(如使用 goto)
- 它无法释放运行时分配的内存
Really, the only time you should exit the problem is with this line in main.cpp:
真的,您应该退出问题的唯一时间是 main.cpp 中的这一行:
return 0;
If you are using exit() to handle errors, you should learn about exceptions (and nesting exceptions), as a much more elegant and safe method.
如果您使用 exit() 来处理错误,您应该了解异常(和嵌套异常),这是一种更加优雅和安全的方法。
回答by Evan Carslake
return 0;
put that wherever you want within int main()
and the program will immediately close.
return 0;
把它放在任何你想要的地方int main()
,程序会立即关闭。
回答by chrisbunney
The program will terminate when the execution flow reaches the end of the main function.
当执行流程到达 main 函数的末尾时,程序将终止。
To terminate it before then, you can use the exit(int status) function, where status is a value returned to whatever started the program. 0 normally indicates a non-error state
要在此之前终止它,您可以使用 exit(int status) 函数,其中 status 是返回到启动程序的任何对象的值。0 通常表示非错误状态
回答by Goz
Either return a value from your main
or use the exit
function. Both take an int. It doesn't really matter what value you return unless you have an external process watching for the return value.
从您的返回值main
或使用该exit
函数。两者都取一个整数。除非您有一个外部进程监视返回值,否则返回什么值并不重要。
回答by Jagannath
If you have an error somewhere deep in the code, then either throw an exception or set the error code. It's always better to throw an exception instead of setting error codes.
如果您在代码深处的某个地方有错误,那么要么抛出异常,要么设置错误代码。抛出异常总是比设置错误代码更好。
回答by Brian Agnew
Generally you would use the exit()
method with an appropriate exit status.
通常,您会使用exit()
具有适当退出状态的方法。
Zero would mean a successful run. A non-zero status indicates some sort of problem has occurred. This exit code is used by parent processes (e.g. shell scripts) to determine if a process has run successfully.
零将意味着成功运行。非零状态表示发生了某种问题。父进程(例如 shell 脚本)使用此退出代码来确定进程是否已成功运行。
回答by Krazy Glew
Beyond calling exit(error_code) - which calls atexit handlers, but not RAII destructors, etc. - more and more I am using exceptions.
除了调用 exit(error_code) - 它调用 atexit 处理程序,但不调用 RAII 析构函数等 - 我越来越多地使用异常。
More and more my main program looks like
我的主程序越来越像
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);
}
}
where secondary_main in where all the stuff that was originally is put -- i.e. the original main is renamed secondary_main, and the stub main above is added. This is just a nicety, so that there isn't too much code between the tray and catch in main.
其中,secondary_main 放置了所有原来的东西——即原来的main 被重命名为secondary_main,并添加了上面的存根main。这只是一个细节,因此托盘和主捕获之间没有太多代码。
If you want, catch other exception types.
I quite like catching string error types, like std::string or char*, and printing those
in the catch handler in main.
如果需要,可以捕获其他异常类型。
我非常喜欢捕获字符串错误类型,例如 std::string 或 char*,并在 main 的 catch 处理程序中打印它们。
Using exceptions like this at least allows RAII destructors to be called, so that they can do cleanup. Which can be pleasant and useful.
使用这样的异常至少允许调用 RAII 析构函数,以便它们可以进行清理。这可以是愉快和有用的。
Overall, C error handling - exit and signals - and C++ error handling - try/catch/throw exceptions - play together inconsistently at best.
总的来说,C 错误处理 - 退出和信号 - 和 C++ 错误处理 - try/catch/throw 异常 - 充其量是不一致的。
Then, where you detect an error
然后,在您检测到错误的地方
throw "error message"
or some more specific exception type.
或更具体的异常类型。