C++ C+;中.dtors和atexit()之间的差异+;

C++ C+;中.dtors和atexit()之间的差异+;,c++,attributes,atexit,C++,Attributes,Atexit,.dtors中的函数与使用atexit()调用的函数有何不同 据我所知,标有((析构函数))属性的函数位于.dtors段中,并在退出后调用。同样,使用atexit(fctName)添加的函数放置在一个数组中,并在正常执行结束后调用 为什么C++提供了两种不同的机制?是否只有一种方法才能完成不同的事情?只能使用atexit()动态添加函数吗 同样是首先调用的,.dtor中的函数或使用atexit()添加的函数?C++没有.dtor。有些实现可能会失败。跟踪全局对象的析构函数是一种合理的机制。据我所

.dtors
中的函数与使用
atexit()调用的函数有何不同

据我所知,标有
((析构函数))
属性的函数位于
.dtors
段中,并在退出后调用。同样,使用
atexit(fctName)
添加的函数放置在一个数组中,并在正常执行结束后调用

为什么C++提供了两种不同的机制?是否只有一种方法才能完成不同的事情?只能使用
atexit()
动态添加函数吗


同样是首先调用的,
.dtor
中的函数或使用
atexit()
添加的函数?

C++没有
.dtor
。有些实现可能会失败。跟踪全局对象的析构函数是一种合理的机制。据我所知,这是一个编译时列表

不过,atexit处理程序是在运行时添加的。这意味着您只能在运行时需要时添加函数


有关问题的最后一部分(以及更多详细信息),请参见

静态对象析构函数的一个合法实现是注册 当构造函数完成时,使用
atexit
将它们删除。标准 要求顺序与使用此实现时的顺序相同。 主要区别在于静态对象的析构函数是 析构函数:如果对象是 完全构造,无需注册 他们。他们有一个
这个
参数来访问对象

编辑:

说得很清楚:给定

T obj;      //  where obj has static lifetime...
编译器将生成一个函数:

void __destructObj()
{
    obj.~T();
}
以及以下初始化代码:

new (&obj) T;
std::atexit( __destructObj );
这与
obj
的范围无关;同样的基本代码也适用于 本地静态和命名空间范围内的对象。(如属 对于本地对象,编译器还必须生成标志和代码 测试它以指示对象是否已经初始化; 它还必须采取措施确保线程安全。)

事实上,很难看出编译器是如何做到这一点的 (尽管它可能会生成内联代码来执行
std::atexit
的功能), 给定订购要求。

在正常进程终止时,通过退出(3)或从程序的main()返回调用atexit()

对于.ctors/.dtor,在加载/卸载定义它们的共享库时会调用它们


这些事件发生的顺序非常明显。

它不可能是一个编译时列表,因为销毁顺序必须与构造顺序相反,并且必须与调用
atexit
@JamesKanze正确交叉:我不明白这到底是个什么问题?
.dtors
列表只是一个编译后的函数指针列表,它作为相应的
.ctors
完成,动态地指向一些
\uuuuuuuuuuuu内部
列表。如果有交错的
atexit()
调用,它们也将被添加到
\uuuuuAtexit\uInternal
列表中。不过,关键是列表是通过合并表项和
atexit()
参数动态构建的。请参阅我对您对我的答案的评论的回复。基本上,您似乎只是在考虑简单的情况,而忽略了本地静态和初始值设定项,它们本身称为
std::atexit
。标准要求注册到
atexit
的函数和静态对象的析构函数的顺序与调用
atexit
和构造函数的顺序相反。是吗?从某种形式的初始编译列表开始,并在需要时(且仅在需要时)动态修改该列表似乎更容易。毕竟,对于许多程序,您永远不会修改初始列表。当你这样做的时候,在一个单链表中拼接一个条目也不是火箭科学。这也是一个合法的解决方案,但可能很棘手。如何确定在何处拼接?实际上,
atexit
将是C库的一部分,并且不知道这个列表。考虑迈尔斯单子的可能性,其中实例> /Cuff>函数具有局部静态,通常会从其他静态对象的构造函数调用,并且其析构函数也必须在正确的位置拼接。C++不提供D.Tor段。这是一个实现细节<代码>析构函数
属性也不是由标准定义的。它是(C)语言的扩展<代码> ATEX/<代码>在C标准中定义,所以可以说它是C++的,因为它是从C继承的。您如何登记<代码>这个< /Cult>指针,用于全局对象的析构函数?在幕后,必须有一些通用的机制(因为交织是有文档记录的行为),但不能简单地重用public
atexit
API。@MSalters编译器必须生成一个不带参数的函数,并注册它。这并不太难,因为它知道对象的地址。另一方面,标准中的排序约束几乎需要动态注册:如果我有
to1;bool b=(标准::atexit(f),真);二氧化钛,标准要求订单
~T(o2);f()~T(o1)。(为什么是另一个问题。任何真正写这类东西的人都应该被枪毙。)看起来有点复杂(那些助手函数的开销可能相当大),但它会起作用,是的。为什么有人会需要这个,我认为令人信服的论点是Andrei Alexandrescu在正确的清理(凤凰ChansLon,Irc,在现代C++设计中)的工作。@ MalSter并不简单,但我认为这个想法是应该有很少的对象具有静态存储持续时间。我可能会补充说早期的C++编译器没有这么做。