外部指针在静态库中为空,当不是静态库时工作正常

Extern pointer is null in static library, worked fine when not a static library

本文关键字:静态 工作 指针 外部      更新时间:2023-10-16

我把我的Visual Studio项目(2015,c++)分成了三个部分:

  • 静态库中的主应用程序
  • 只有main函数的可执行文件
  • 使用静态.lib文件的单元测试,以便可以导入所需的类并对其进行单元测试。

在我把它分成lib/exe/tests之前,主应用程序只是一个独立的可执行文件,它运行得非常好。

现在我不能只运行main函数的可执行文件,单元测试也不能因为某个指针总是空的。唯一的主要区别是,我在这个例子中使用了一个原始指针,但我在我的代码中使用了一个unique_ptr(目前,我切换到原始指针只是为了确保下面的例子是尽可能准确的,它没有神奇地编译/运行正确的原始指针)。

代码看起来与下面的代码非常相似(额外的代码被删除了):

// console.hpp
extern Console *console;

实现cpp文件(只包含需要的部分):

// console.cpp
Console *console = new Console();

现在在一些不相关的函数中,由于控制台指针是nullptr,这段代码失败了:

// some_other_file.cpp
#include "console.hpp"
    // Inside some function...
    console->doSomething();  // console is NULL
同样,我的代码在一个项目中工作得很好。无论如何,它编译得很好,没有链接错误,即使它被分成3个部分,但现在指针总是空的。

最后一个有趣的注意事项是,全局和外部的非指针变量都可以工作。这是否仅限于指针/unique_ptrs?

这是可以通过单例模式修复的吗?

线索在这条注释中:"似乎在主函数之前调用了其他代码,这些代码不让全局变量初始化。"

引用console的代码可能是作为另一个全局变量初始化的一部分运行的,在这种情况下,发生在console初始化之前。你必须非常小心地确保你没有依赖于全局初始化器的顺序。在拆分程序之前,你可能很幸运,现在你的运气已经用完了。

解决这个问题最简单的方法是使用单例模式。不是让程序的其他部分直接引用指针,而是让它们调用返回指针的函数,该函数将第一次初始化指针。这可以确保在使用它之前对它进行初始化。

这里有一个常见的模式:

Console *GetConsole() {
    static Console *console = new Console();
    return console;
}

现在console不再是一个全局变量。所有想要访问控制台的东西都调用GetConsole

函数局部静态变量将在第一次调用函数时初始化,之后它只返回值。如果您有多个线程和较旧的编译器,则必须做更多的工作来防止可能的竞争条件。现代编译器应该以线程安全的方式进行初始化。