C++结束线程:如何结束 C++ 代码(how to code with c++)

我想我的 C ++ 代码停止运行,如果满足一定的条件,但我不知道如何做到这一点。所以在任何时候,如果if语句是真的终止代码是这样的:

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

有几种方法,但首先你需要了解为什么对象清理很重要,因此std::exit在 C ++ 程序员中被边缘化的原因。

RAII 和堆栈展开

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);
}

在每种可能性中发生的事情是:

可能性 1:返回基本上离开当前函数范围,因此它知道os的生命周期结束,从而调用其析构函数并通过关闭和刷新文件到磁盘来进行适当的清理。

可能性 2:抛出异常还可以照顾当前范围内对象的生命周期,从而进行适当的清理...

可能性 3:此处堆栈展开进入操作!即使在inner_mad处引发异常,展开器仍将通过madmain的堆栈进行适当的清理,所有对象都将被正确销毁,包括ptros

可能性 4:好吧,这里?exit是一个 C 函数,它不知道也不兼容 C ++ 习语。它不会对您的对象执行清理,包括相同范围内的os。因此,您的文件将无确关闭,因此内容可能永远不会写入其中!

其他可能性:通过执行隐式return 0,它将离开主作用域,从而具有与可能性 1 相同的效果,即适当的清理。

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

结束的可能方式

从 Main 回来!

你应该尽可能这样做;总是喜欢从程序返回,从 main 返回一个正确的退出状态。

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

然而,你可能在调用堆栈很深,并返回所有可能是痛苦的...

[不] 抛出异常

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

但是这里是catch!它是实现定义的,当抛出的异常未被处理时,是否执行堆栈展开(由 catch (...) 子句),或者即使您在调用堆栈的中间有一个noexcept函数。这在§ 15.5.1 [except.terminate]中有说明:

在某些情况下,必须放弃异常处理,以获得不太微妙的错误处理技术。[注意:这些情况是:

[...]

-当异常处理机制找不到抛出的异常的处理程序时 (15.3),或者当搜索处理程序 (15.3) 遇到不允许异常的noexcept-规范的函数的最外层块时 (15.4),或者 [...]

[...]

在这种情况下,std::terminate () 被调用 (18.8.3)。在找不到匹配处理程序的情况下,std::terminate () 被调用之前堆栈是否被展开是实现定义的[...]

所以我们必须抓住它!

做抛出一个异常,并抓住它在主!

由于未捕获的异常可能不会执行堆栈展开(因此不会执行正确的清理),我们应该在 main 中捕获异常,然后返回退出状态(EXIT_SUCCESSEXIT_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会导致程序正常终止,仅此而已。

std::quick_exit导致程序正常终止并调用std::at_quick_exit处理程序,不执行其他清理。

std::exit导致正常的程序终止,然后调用std::atexit处理程序。执行其他类型的清理,例如调用静态对象析构函数。

std::abort导致程序异常终止,不执行清理。如果程序以非常非常意外的方式终止,则应调用此方法。它只会向操作系统发送有关异常终止的信号。在这种情况下,某些系统会执行核心转储。

std::terminate调用std::terminate_handler,默认情况下调用std::abort

63

正如马丁 · 约克(Martin York)提到的那样,出口不会像退货那样进行必要的清理。

在退出的地方使用 return 总是更好的。如果你不在 main 中,无论你想退出程序,首先返回 main。

考虑下面的例子。使用下面的程序,将创建一个包含所提到内容的文件。但是如果 return 是 commented & amp;uncommented exit (0),编译器不会保证该文件将具有所需的文本。

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

不仅如此,在程序中具有多个退出点会使调试更加困难。仅在合理的情况下使用 exit。

40

调用std::exit函数。

23

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

您最终将从程序中获得多个退出点

它使代码更复杂(如使用 goto)

它不能释放在运行时分配的内存

真的,你应该退出问题的唯一时间是在 main.cpp 中的这一行:

return 0;

如果您使用 exit()处理错误,您应该了解异常(和嵌套异常),作为一个更优雅和安全的方法。

本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处

(991)
目录网站源码:显示目录列表的网站(website showing directory listing)
上一篇
Cyclone 3:如何在AlteraCycloneVFPGA中控制路由
下一篇

相关推荐

  • codecombat手机版下载使用CodeCombat手机版

    手机版下载:在手机上安装应用,可以在App Store和Google Play上搜索“”,下载并安装。…

    2023-03-13 13:48:55
    0 21 12
  • 牛牛源码:用 leetcode解释牛牛算法

    关于牛牛源码的问题,在bulls and cows leetcode中经常遇到,算法在这里:https://discuss.leetcode.com/topic/28463/one-pass-java-solution。…

    2022-11-23 08:48:03
    0 66 31
  • android 视频编码深入理解MediaCodec API

    Android 视频编码是指将原始视频数据经过压缩编码后,生成新的视频数据,以便减少视频文件的体积,提高传输速度,以及更好地在 Android 设备上播放。…

    2023-01-13 10:58:18
    0 23 78
  • cv小敢:如何利用CV小敢提升职业技能?

    cv小敢(Computer Vision Tiny-YOLO)是一种轻量级的物体检测算法,它可以在资源受限的设备上运行,如嵌入式设备、智能手机等。它是基于YOLO(You Only Look Once)算法的一个变体,由Joseph Redmon和Ali Farhadi开发,旨在提高深度学习模型的性能,同时减少模型的大小和计算复杂度。…

    2023-02-09 13:08:59
    0 86 24
  • coremail论客邮箱Coremail论客邮箱

    Coremail论客邮箱是一款专业的企业邮箱服务,可以满足企业对安全、可靠性和高效性的要求。它拥有强大的安全性能,可以提供多种安全保护,包括防止邮件被窃取、拦截恶意邮件、防止跨站脚本攻击等。此外,它还支持多种企业级功能,如组织架构管理、收发邮件管理、文件共享管理、联系人管理等,可以帮助企业提高工作效率,提升企业形象。…

    2023-02-25 04:36:55
    0 61 82
  • linux 编译静态库:```ar cr libtest.a *.o```4. 完成!

    我们要创建一个源文件,比如:mylib.c,内容如下:#include…

    2023-03-19 08:46:39
    0 54 36
  • canvas下载安装:Unleash the Power of Canvas to Create Amazing Visuals

    Canvas是一种HTML5技术,可以在网页上创建和绘制2D图形。它是一个JavaScript API,可以使用JavaScript代码来绘制图形,并且可以添加各种效果,如阴影,渐变,动画等。…

    2023-03-08 00:48:14
    0 34 98
  • class定位:The Benefits of Using Class Selectors for Element Locati

    示例示例class定位是一种CSS布局技术,用于指定HTML元素的位置,可以使元素放置在页面的任何位置。代码示例:…

    2023-03-06 07:16:44
    0 20 40

发表评论

登录 后才能评论

评论列表(79条)