【发布时间】:2015-05-14 08:54:47
【问题描述】:
在 C 和 C++ 中,atexit 函数要么在 exit 内部调用,要么在 main 返回之后(名义上调用 exit:__libc_start_main(argc,argv) { __libc_constructors(); exit(main(argc,argv)); })。
有没有办法确定我们是否在退出序列中? C++ 全局和局部静态的析构函数在atexit 注册,所以你的代码当然可以在这个阶段被调用。 (有趣的是,在某些平台上,如果您尝试在 exit 中创建 C++ 本地静态对象,它会在退出锁上死锁!)
到目前为止我最好的尝试如下:
static bool mainExited = false;
static void watchMain() {
static struct MainWatcher {
~MainWatcher() { mainExited = true; }
} watcher;
}
当你想观察退出时,你调用watchMain(),mainExited 随时告诉你退出序列是否已经开始——当然,如果稍后初始化的本地静态对象正在破坏!
是否可以改进该技术以纠正此问题,或者是否有其他方法可行?
除此之外 - 用例!
虽然从语言的角度来看这个问题很有趣(有点像“我可以判断我是否在 catch 块内吗?”),但概述用例也很有用。我在编写一些代码时遇到了这个问题,这些代码将在加载和不加载 JVM 的情况下运行(直接调用或通过 JNI 调用)。 JVM退出后,调用Catexit处理程序,如果类加载器没有卸载JNI共享库,则不调用JNI_OnUnload。
由于共享库的对象可以通过显式销毁(并且应该释放它们的资源)和退出时的清理来销毁,我需要安全地区分这两种情况,因为当我们到达出口时 JVM 已经消失了代码!基本上没有一点嗅探,我无法在 JNI 规范/文档中找到一个共享库来知道 JVM 是否仍然存在,如果它消失了,那么尝试释放我们拥有的引用肯定是错误的到 Java 对象。
【问题讨论】:
-
你能解释一下这个用例吗?
-
在 main 中创建一个记录其销毁的对象。如果它是第一个创建的对象,它的析构函数将是 main 返回之前调用的最后一个函数。
-
@Benjamin 我记得在
main中创建的对象不会在exit中被破坏,只有全局和局部静态?那么您是否建议在 main 内部使用本地静态 - 在这种情况下,这与我的解决方案几乎相同。 -
为什么不在
main中使用本地非静态对象来检测您是否要离开main? -
我这里没有“现代 C++ 设计”,但 Andrei Alexandrescu 在他的书中对这类 post-main 问题进行了详细分析。
标签: c++ static posix main exit