我正在研究一些C ++代码,我遇到了一个问题,这个问题一直困扰着我...假设我正在Linux主机上用GCC编译ELF目标,那么全局静态构造函数和析构函数叫做?
我听说crtbegin.o中有一个函数_init,crtend.o中有函数_fini。这些是由crt0.o调用的吗?或者动态链接器是否实际检测到它们在加载的二进制文件中的存在并调用它们如果是这样,当实际上是在调用它们吗?
我最感兴趣的是,因为我的代码在运行时被加载,执行然后卸载,所以我可以理解幕后发生的事情。
提前致谢!
更新:我基本上试图弄清楚构造函数被调用的一般时间。我不想根据这些信息在我的代码中做出假设,或多或少地更好地了解我的程序加载时在较低级别发生的事情。我知道这是特定于操作系统的,但我试图在这个问题上稍微缩小一点。
答案 0 :(得分:18)
在谈论非本地静态对象时,没有太多保证。正如您已经知道的(这里也提到过),它不应该编写依赖于它的代码。静态初始化命令惨败...
静态对象经历两阶段初始化:静态初始化和动态初始化。前者首先发生,并通过常量表达式执行零初始化或初始化。后者在所有静态初始化完成后发生。例如,这是在调用构造函数时。
通常,此初始化发生在main()之前的某个时间。然而,与许多人认为的相反,即使C ++标准无法保证。实际上保证的是,在使用与正被初始化的对象相同的转换单元中定义的任何函数或对象之前完成初始化。请注意,这不是特定于操作系统的。这是C ++规则。以下是标准的引用:
无论是否对象的动态初始化(8.5,9.4,12.1,12.6.1),它都是实现定义的 命名空间范围在main的第一个语句之前完成。如果初始化推迟到某一点 在第一个main语句之后的时间内,它应该在第一次使用任何定义的函数或对象之前发生 在与要初始化的对象相同的翻译单元中
答案 1 :(得分:11)
这不是特定于操作系统,而是特定于编译器。
您已给出答案,初始化在__init
完成。
对于第二部分,在gcc中,您可以保证初始化顺序,____attribute____((init_priority(PRIORITY)))
附加到变量定义,其中PRIORITY
是某个相对值,首先初始化较小的数字。
答案 2 :(得分:10)
这很大程度上取决于编译器和运行时。对构建全局对象的时间做出任何假设都不是一个好主意。
如果您的静态对象依赖于已经构建的另一个静态对象,则这尤其成问题。
这称为“static initialization order fiasco”。即使代码中不是这种情况,关于该主题的C ++ Lite FAQ文章也值得一读。
答案 3 :(得分:6)
您拥有的受助人:
如果你有彼此依赖的全局变量,你有两个选择:
class AType
{ AType() { log.report("A Constructed");}};
LogType log;
AType A;
// Or
Class AType()
{ AType() { getLog().report("A Constructed");}};
LogType& getLog()
{
static LogType log;
return log;
}
// Define A anywhere;
在这里,您必须承认对象日志在对象B之前没有被销毁。这意味着必须在B之前完全构造日志(因为随后将应用销毁规则的相反顺序)。同样可以使用相同的技术。要么将它们放在同一个翻译单元中,要么使用函数来获取日志。
class BType
{ ~BType() { log.report("B Destroyed");}};
LogType log;
BType B; // B constructed after log (so B will be destroyed first)
// Or
Class BType()
{ BType() { getLog();}
/*
* If log is used in the destructor then it must not be destroyed before B
* This means it must be constructed before B
* (reverse order destruction guarantees that it will then be destroyed after B)
*
* To achieve this just call the getLog() function in the constructor.
* This means that 'log' will be fully constructed before this object.
* This means it will be destroyed after and thus safe to use in the destructor.
*/
~BType() { getLog().report("B Destroyed");}
};
LogType& getLog()
{
static LogType log;
return log;
}
// Define B anywhere;
答案 4 :(得分:5)