1

我有一个.cpp文件(我们称之为statinit.cpp)编译并链接到我的可执行文件中,使用gcc. 我的main()功能不在.statinit.cpp

statinit.cpp有一些我需要运行的静态初始化。但是,我从不明确引用statinit.cppmymain()中的任何内容,或者它引用的任何内容。发生的事情(我想)是从创建的链接对象statinit.cpp永远不会在运行时加载,所以我的静态初始化永远不会运行,导致代码其他地方出现问题(这很难调试,但我最终跟踪它)。

是否有标准库函数、链接器选项、编译器选项或可以让我强制该对象在运行时加载而不引用其元素之一的东西?

我想做的是在 statinit.cpp 中定义一个虚拟函数,在main()看到的头文件中声明它,然后从main(). 但是,这是一个非常丑陋的解决方案,我非常想避免对 statinit.cpp 本身进行更改。

谢谢,丹尼尔

4

8 回答 8

4

目前尚不清楚问题是什么:

C++ 没有静态初始化器的概念。
所以有人假设你在“文件范围”中有一个对象。

  • 如果这个对象在全局命名空间中,那么它将在 main() 被调用之前被构造并在 main() 退出之后被销毁(假设它在应用程序中)。
  • 如果此对象位于命名空间中,则实现可以选择延迟初始化变量。这只是意味着它将在首次使用之前完全初始化。因此,如果您依赖于构造的副作用,则将对象放在全局命名空间中。

现在,您可能看不到该对象执行的构造函数的一个原因是它没有链接到应用程序中。这是链接器问题,而不是语言问题。当对象被编译成静态库并且您的应用程序随后链接到静态库时,就会发生这种情况。链接器只会加载从应用程序显式引用的应用程序函数/对象(即解析符号表中未定义事物的事物)。

要解决这个问题,您有几个选择。

  • 不要使用静态库。
    • 编译成动态库(现在的规范)。
    • 将所有源代码直接编译到应用程序中。
  • 从 main 中明确引用该对象。
于 2009-12-21T16:27:15.353 回答
2

我遇到了同样的问题。

写一个文件,DoNotOptimizeAway.cpp

void NoDeadcodeElimination()
{
    // Here use at least once each of the variables that you'll need.
}

然后NoDeadcodeElimination()从调用main

编辑:或者,您可以编辑链接器选项并告诉它始终链接所有内容,即使它没有被使用。我不喜欢这种方法,因为可执行文件会变得更大。

于 2009-12-21T12:50:58.270 回答
1

这些问题以及这些潜在解决方案的问题都围绕着这样一个事实,即您不能对静态初始化做出太多保证。因此,既然它不可靠,就不要依赖它!

使用静态“InitializeLibrary”类型的静态函数显式初始化数据。现在你保证它会发生,并且你保证它什么时候根据你调用的时间与其他代码相关。

于 2009-12-21T13:42:19.887 回答
1

一种 C++'ish 方法是使用 Singletons。

本质上,编写一个函数来返回对对象的引用。要强制它初始化,请将其设为函数内的静态对象。

制作一个大致像这样的类静态函数:

class MyClass {
   static MyClass& getObject()
   {
        static MyObject obj;
        return obj;
    }
};
于 2009-12-21T14:26:15.470 回答
0

阅读 ld 命令的手册页并查看 -u 选项。如果 statinit.cpp 定义了任何看起来像函数的东西,那么尝试在 -u 中命名它。否则选择一个在 statinit.cpp 中定义的数据对象并在 -u 中命名,并希望它有效。我认为最好编写命令行,这样 -u 选项就在你的库的 -l 选项之前,其中包含 statinit 的目标代码。

于 2009-12-22T02:22:01.230 回答
0

当然动态库解决方案是最好的,但我也被告知可以使用链接器选项链接整个静态库:

-Wl,-whole-archive

在图书馆的-l选择之前,和

-Wl,-no-whole-archive

在它之后(也避免将其他库作为一个整体包括在内)。

于 2009-12-22T07:55:23.757 回答
0

由于您使用的是 C++,因此您始终可以声明一个全局对象(即引用statinit.cpp.跑。

不过,有一个非常重要的警告。无法保证何时调用构造函数,也无法明确地对每个构造函数何时被调用进行排序。这也可能会挫败任何检查内存泄漏的尝试,因为您不能再保证在运行 main 时分配的所有内存都已被释放。

于 2009-12-21T13:23:16.057 回答
0

是静态项从未初始化的问题,还是在您需要使用静态项时未初始化的问题?

所有静态初始化都应该在您的 main() 运行之前完成。但是,如果使用另一个静态对象对静态对象进行初始化,则可能会遇到问题。(注意:如果您使用的是 int 等原语,则这不适用)

例如,如果您在文件 x.cpp 中有:

static myClass x(someVals);

在 y.cpp 中:

static myClass y = x * 2; 

系统可能会在创建 x 之前尝试实例化 y。在这种情况下,“y”变量可能为 0,因为 x 在初始化之前可能为 0。

一般来说,最好的解决方案是在第一次使用对象时实例化它(如果可能的话)。但是,我在上面注意到您不允许修改该文件。该文件中的值是否正在其他地方使用,也许您可​​以更改访问这些值的方式?

于 2009-12-21T14:39:14.033 回答