【问题标题】:What is the difference between __cxa_atexit() and atexit()__cxa_atexit() 和 atexit() 有什么区别
【发布时间】:2017-03-20 19:09:49
【问题描述】:

GCC docs 中,我找到了-fuse-cxa-atexit 选项,它显示以下内容:

完全符合标准的静态析构函数处理需要此选项

那么这两者有什么区别呢?在__cxa_atexit 的文档中,我发现了以下内容:

__cxa_atexit()函数用于实现atexit()

我正在函数中实现静态(不要问为什么),我想知道使用 2 个中的哪一个来调用析构函数。

我想我只有 atexit() 用于 MSVC?有问题吗?

我可以在任何地方都使用atexit() 并确保它的行为就像函数中的真实静态对象一样吗?

【问题讨论】:

    标签: c++ atexit


    【解决方案1】:

    __cxa_atexit() 在 Itanium C++ ABI 中定义。文档解释了motivation behind this function

    C++ 标准要求在程序以相反的构造顺序退出时为全局对象调用析构函数。大多数实现都通过调用 C 库 atexit 例程来注册析构函数来处理这个问题。这是有问题的,因为 1999 C 标准只要求实现支持 32 个注册函数,尽管大多数实现支持更多。更重要的是,它根本不涉及在大多数实现中通过在程序终止之前调用 dlclose 从正在运行的程序映像中删除 [动态共享对象] 的能力。

    下面指定的 API 旨在在正常程序退出期间提供符合标准的处理,包括以相对于构造函数注册的析构函数的正确顺序执行 atexit 注册的函数,以及在早期 DSO 卸载期间的合理处理(例如 @ 987654330@)。

    所以:

    • __cxa_atexit() 不限于 32 个函数。
    • __cxa_atexit()会在程序退出前卸载动态库时调用该动态库的static的析构函数。

    应该启用-fuse-cxa-atexit,如果您正在编写库,并且您的 libc 具有此功能(例如 glibc、musl)。事实上,你的发行版附带的 gcc 可能已经自动启用了这个标志(如果你启用了这个标志并且 libc 不支持它,则会出现链接器错误)。

    注意users should not call __cxa_atexit directly:它接受只有编译器/链接器应该知道的参数 (the __dso_handle)。

    … 不支持__cxa_atexit 的用户界面,因此用户无法使用参数或家庭DSO 注册atexit 函数。


    MSVC 显然 does not use atexit()-like functions 运行全局析构函数。根据Destructor of a global static variable in a shared library is not called on dlclose,MSVC 已经在dlclose() 上运行析构函数。

    【讨论】:

    • soooooo 用于模拟本地静态变量的生命周期 - 仅使用 atexit() 不会与编译器生成的 100% 相同?
    • @onqtam 对。代替atexit,您可以创建一个本地结构,析构函数调用该处理程序。 static struct Foo { ~Foo() { handle(foo); } } foo_dtor;
    • 第一行有一个错字:Italium C++ ABI。应该是 Itanium C++ ABI。不幸的是,stackoverflow 不允许我编辑更改少于 6 个字符的帖子。
    • @morty 谢谢,已修复
    猜你喜欢
    • 2018-10-26
    • 2010-09-05
    • 2010-10-02
    • 2011-12-12
    • 2010-09-16
    • 2012-03-14
    • 2012-02-06
    • 2011-02-25
    • 2011-11-22
    相关资源
    最近更新 更多