静态变量初始化顺序
C ++保证编译单元(.cpp文件)中的变量按照声明的顺序进行初始化。 对于编译单元的数量,这个规则分别适用于每个单元(我是指类之外的静态变量)。
但是,变量初始化的顺序在不同的编译单元中是未定义的。
我在哪里可以看到关于gcc和MSVC的这个命令的一些解释(我知道依赖于这是一个非常糟糕的主意 - 它只是了解我们在移植到新的GCC主要版本和不同的操作系统时可能会遇到的遗留代码问题) ?
如您所说,订单在不同的编译单元中是未定义的。
在同一个编译单元中,顺序已被很好地定义:与定义的顺序相同。
这是因为这不是在语言级别解决,而是在链接器级别解决。 所以你真的需要查看链接器文档。 虽然我真的怀疑这会有助于任何有用的方式。
对于gcc:查看ld
我发现即使改变被链接的目标文件的顺序也可以改变初始化顺序。 所以它不仅仅是你需要担心的链接器,而且链接器是如何被你的构建系统调用的。 即使试图解决这个问题实际上也不是首发。
这通常只是初始化在自己初始化时引用对方的全局性问题(因此只影响具有构造函数的对象)。
有技巧来解决这个问题。
我期望模块之间的构造函数顺序主要是将对象传递给链接器的顺序的函数。
但是,GCC可以让你使用init_priority
来显式指定全局init_priority
的顺序:
class Thingy
{
public:
Thingy(char*p) {printf(p);}
};
Thingy a("A");
Thingy b("B");
Thingy c("C");
按照您的预期输出'ABC',但是
Thingy a __attribute__((init_priority(300))) ("A");
Thingy b __attribute__((init_priority(200))) ("B");
Thingy c __attribute__((init_priority(400))) ("C");
输出'BAC'。
既然你已经知道,除非绝对必要,否则你不应该依赖这些信息。 我对各种工具链(MSVC,gcc / ld,clang / llvm等)的一般观察是,将对象文件传递给链接器的顺序是它们将被初始化的顺序。
这也有例外,我并不是要求所有这些,但这些是我自己碰到的那些:
1)4.7之前的GCC版本实际上是以链接线的相反顺序初始化的。 海湾合作委员会的这张票是变化发生的时候,它打破了很多依赖于初始化顺序(包括我的!)的程序。
2)在GCC和Clang中,使用构造函数的优先级可以改变初始化顺序。 请注意,这只适用于被声明为“构造函数”的函数(即它们应该像全局对象构造函数那样运行)。 我尝试过使用像这样的优先级,并发现即使在构造函数的最高优先级上,所有没有优先级的构造函数(例如普通全局对象,没有优先级的构造函数)都将首先被初始化。 换句话说,优先权只与优先权的其他职能相关,但真正的一等公民是没有优先权的公民。 更糟糕的是,由于上述第(1)点,此规则在4.7之前在GCC中恰恰相反。
3)在Windows上,有一个名为DllMain()的非常整齐有用的共享库(DLL)入口函数,如果已定义,它将在所有全局数据初始化后直接运行参数“fdwReason”等于DLL_PROCESS_ATTACH,并且在使用应用程序之前有机会调用DLL上的任何函数。 这在某些情况下非常有用,并且在其他具有GCC或Clang与C或C ++的平台上绝对没有类似的行为。 最接近你会发现一个具有优先级的构造函数(参见上面的第(2)点),这绝对不是一回事,也不适用于DllMain()工作的许多用例。
4)如果你正在使用CMake来生成你的构建系统,我经常这样做,我发现输入源文件的顺序将是它们赋予链接器的结果对象文件的顺序。 但是,通常您的应用程序/ DLL也会链接到其他库中,在这种情况下,这些库将位于输入源文件之后的链接行中。 如果您希望让全局对象之一成为第一个初始化对象,那么您很幸运,并且可以将包含该对象的源文件放在源文件列表中的第一个。 但是,如果您希望有一个是最后一个初始化(可以有效地复制DllMain()行为!),那么您可以使用该源文件调用add_library()以生成静态库,然后添加生成的静态库作为您的应用程序/ DLL的target_link_libraries()调用中的最后一个链接依赖项。 要小心,在这种情况下,您的全局对象可能会得到优化,您可以使用--whole-archive标志来强制链接器不要删除该特定微型归档文件的未使用符号。
关闭提示
要绝对知道链接的应用程序/共享库的结果初始化顺序,请将--print-map传递给ld链接器,并将.init_array传递给grep(或者在4.7之前的GCC中,grep中为.ctors)。 每个全局构造函数都将按照它的初始化顺序打印,并记住4.7之前GCC中的顺序相反(参见上面的第(1)点)。
写这个答案的动机是我需要知道这些信息,别无选择,只能依赖初始化顺序,并且在其他SO帖子和互联网论坛中只找到这些信息的稀疏位。 其中大部分是通过大量实验学到的,我希望这可以为一些人节省时间!
链接地址: http://www.djcxy.com/p/78837.html