如何在C ++中加载未引用的对象?

时间:2009-12-21 12:43:40

标签: c++ loader

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

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

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

我想要做的是在statinit.cpp中定义一个虚函数,在main()看到的头文件中声明它,并从main()调用该虚函数。但是,这是一个非常难看的解决方案,我非常希望避免在statinit.cpp中进行更改。

谢谢, 丹尼尔

8 个答案:

答案 0 :(得分:4)

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

C ++没有静态初始化器的概念 因此,假设您在“文件范围”中有一个对象。

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

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

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

  • 不要使用静态库。
    • 编译成动态库(现在的规范)。
    • 直接将所有源代码编译到应用程序中。
  • 从main中明确引用该对象。

答案 1 :(得分:2)

我遇到了同样的问题。

写一个文件DoNotOptimizeAway.cpp

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

然后从NoDeadcodeElimination()致电main

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

答案 2 :(得分:1)

这些问题以及这些潜在解决方案的问题都围绕着这样一个事实,即您无法保证静态初始化。因为它不可靠,所以不要依赖它!

使用静态“InititalizeLibrary”类型的静态函数显式初始化数据。现在你可以保证它会发生,并且你会根据你打电话的时候保证它与其他代码相关。

答案 3 :(得分:1)

一个C ++'这样做的方法是使用Singletons。

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

创建一个类似于静态函数的静态函数:

class MyClass {
   static MyClass& getObject()
   {
        static MyObject obj;
        return obj;
    }
};

答案 4 :(得分:0)

由于您使用的是C ++,因此您始终可以声明一个全局对象(即引用statinit.cpp中的类的全局变量。一如既往,构造函数将在初始化时调用,因为该对象是全局的,将在main()运行之前调用。

但有一个非常重要的警告。无法保证何时调用构造函数,并且无法在调用每个构造函数时显式排序。这也可能会破坏任何检查内存泄漏的尝试,因为您无法再保证在运行main时分配的所有内存都已被释放。

答案 5 :(得分:0)

静态项目永远不会初始化的问题,还是静态项目在您需要使用时未初始化的问题?

所有静态初始化应该在main()运行之前完成。但是,如果使用另一个静态对象初始化静态对象,则可能会遇到问题。 (注意:如果您使用诸如int之类的基元

,则不适用

例如,如果你有文件x.cpp:

static myClass x(someVals);

在y.cpp中:

static myClass y = x * 2; 

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

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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

-Wl,-whole-archive

在库的-l选项之前,

-Wl,-no-whole-archive

之后(为了避免包括整个其他库)。