C++ 在链接静态库时初始化静态对象

C++ 在链接静态库时初始化静态对象,c++,static-libraries,ld,C++,Static Libraries,Ld,初始化另一个共享库中声明的静态对象的规则是什么?例如,考虑以下内容: 文件X.hpp: struct X { X (); static X const s_x; }; struct Y { Y (X const &) {} }; 文件X.cpp: #include "X.hpp" #include <iostream> X::X () { std::cout << "side effect"; } X const X::s_x;

初始化另一个共享库中声明的静态对象的规则是什么?例如,考虑以下内容:

文件X.hpp:

struct X {
   X ();
   static X const s_x;
};

struct Y {
   Y (X const &) {}
};
文件X.cpp:

#include "X.hpp"
#include <iostream>

X::X ()
{
   std::cout << "side effect";
}

X const X::s_x;
只有(1)或(2),什么也不会发生。但如果我添加(3),静态对象将被初始化(即打印“副作用”)。(我使用通用条款4.6.1)

有没有办法预测这里会发生什么

我不明白指令(2)如何不强制默认构造
X::s_X
对象,而指令(3)却强制默认构造

编辑:生成命令:

g++ -c X.cpp
g++ -c main.cpp
ar rcs libX.a X.o
g++ -o test main.o -L. -lX

默认情况下,在许多平台上,如果您的程序没有引用静态库中给定对象文件中的任何符号,则整个对象文件(包括静态初始值设定项)将被删除。因此链接器忽略了libX.a中的X.o,因为它看起来像是未使用的

这里有几个解决方案:

  • 不要依赖于静态初始值设定项的副作用。这是最便携/简单的解决方案
  • 以编译器无法看穿的方式引用伪符号,从而在每个文件上引入一些伪依赖项(例如将地址存储到外部可见的全局文件中)
  • 使用一些特定于平台的技巧来保留有问题的对象。例如,在Linux上,您可以使用
    -Wl、-wholearchive a.o b.a-Wl、-no-whole archive

  • 有趣的问题。你用过哪些编译器?我可以用VS2008复制。请注意,如果将X设为非空,它似乎会按预期工作。问题是为什么?您是否禁用了所有优化?我知道,它不应该优化有效的副作用,但仍然。。。也许值得一试。@julkiewicz我用-O0编译,但这是gcc的默认值。也许它没有禁用所有功能,我不知道(我会查看文档)。你用英语描述了很多东西(这很糟糕,因为它太不准确)。最好记下执行每个操作时使用的确切命令。这使它更准确了。我不确定我是否理解。我的程序使用
    X::s_X
    ;这不是X.o中的“符号”吗?(当然,它在X.o中由nm-C列出);但是,对X::s_X的一个微不足道的使用(从某种意义上说,您实际上并没有写入它,或者没有以影响程序输出的方式使用该值)可以被视为根本没有引用它。如果非常明显没有使用该变量,那么即使在-O0(如案例1和案例2)时也会对其进行优化。因此,该标准没有指定任何关于链接存档时发生的情况的内容?在这种情况下,我发现当我把两个文件编译在一起,当我用X.cpp(<)>代码>建立一个库,然后链接到它时,程序就没有什么相同的行为。C++标准对文件一无所知。有一种语言允许任意延迟静态变量的初始化,直到使用同一翻译单元(即源文件)中的某些内容。当然,如果从未使用过函数或变量,“从不”在第一次使用之前。严格地说,我认为您的测试用例(1)和(2)中的转换违反了标准。。。但这有点像边缘案件。
    g++ -c X.cpp
    g++ -c main.cpp
    ar rcs libX.a X.o
    g++ -o test main.o -L. -lX