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>指针,用于全局对象的析构函数?在幕后,必须有一些通用的机制(因为交织是有文档记录的行为),但不能简单地重用publicatexit
API。@MSalters编译器必须生成一个不带参数的函数,并注册它。这并不太难,因为它知道对象的地址。另一方面,标准中的排序约束几乎需要动态注册:如果我有to1;bool b=(标准::atexit(f),真);二氧化钛代码>,标准要求订单~T(o2);f()~T(o1)代码>。(为什么是另一个问题。任何真正写这类东西的人都应该被枪毙。)看起来有点复杂(那些助手函数的开销可能相当大),但它会起作用,是的。为什么有人会需要这个,我认为令人信服的论点是Andrei Alexandrescu在正确的清理(凤凰ChansLon,Irc,在现代C++设计中)的工作。@ MalSter并不简单,但我认为这个想法是应该有很少的对象具有静态存储持续时间。我可能会补充说早期的C++编译器没有这么做。