代码之家  ›  专栏  ›  技术社区  ›  jabaa

为什么库中没有调用全局变量的构造函数?

  •  2
  • jabaa  · 技术社区  · 2 年前

    我有一些带有一些单例类的遗留代码,这些类使用全局变量的构造函数进行注册。这是一个很大的代码库,它被编译成一个可执行文件。我尝试过组织代码库,并将代码重新组合到库中。当前代码的一个最小示例是

    main.cpp

    int main(int argc, char *argv[])
    {
      return 0;
    } 
    

    哈希.cpp

    #include <iostream>
    
    class Hash
    {
    public:
        Hash()
        {
            std::cout << "Hash\n";
        }
    };
    
    Hash a;
    

    并且当前生成配置为

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.26)
    project(mcve)
    
    add_executable(mcve main.cpp Hash.cpp)
    

    构建代码并运行可执行文件打印

    Hash
    

    我已将生成配置修改为

    cmake_minimum_required(VERSION 3.26)
    project(mcve)
    
    add_library(Hash Hash.cpp)
    add_executable(mcve main.cpp)
    target_link_libraries(mcve Hash)
    

    这将创建一个静态库 libHash.a 并将其链接到可执行文件。编译相同的代码并运行可执行文件不会打印任何内容。为什么会有差异,在哪里描述?它是C++标准的一部分还是编译器的一部分?它是特定于操作系统的(Linux静态库)吗?这是未定义的行为吗?

    0 回复  |  直到 2 年前
        1
  •  10
  •   Sam Varshavchik    2 年前

    区别应该在链接器的文档以及介绍性教科书中描述,我想,这些教科书解释了什么是静态库,它们是如何工作的,以及如何使用它们。

    图片中没有静态库:当翻译单元明确地链接在一起时,其中的所有内容都成为可执行文件的一部分。

    在你的第一个例子中 main.cpp hash.cpp 链接到 mcve 可执行文件,并且在启动时唯一的全局对象来自 hash.cpp 构建。结束。

    我重复一遍,与静态库链接不会, 包括 每件事 从静态库到可执行文件。静态库不是这样工作的。只有静态库中导出与静态库链接的翻译单元中未定义符号的单个翻译单元——只有这些翻译单元链接到可执行文件中(事实上,这有点复杂,但对于这个问题来说,完全的复杂性是无关紧要的,只会混淆事情,所以我们只使用这个简化的描述)。这是静态库的一个定义特征。

    对所显示的代码进行非常非常仔细的检查,会发现中没有未定义或未解决的符号 main.cpp 由导出 hash.cpp 所以 hash.cpp 未链接到可执行文件 。全局对象在中定义 hash.cpp 因此,最终的可执行文件在程序运行时不会出现任何需要构造的全局对象。结束。

    这并不是说静态库的初始化或构造规则发生了变化。这是因为没有什么可以初始化或构造的。