静态变量被初始化两次

2023-11-25

考虑我在编译单元中有一个静态变量,它最终出现在static库 libA.然后我有另一个编译单元访问这个变量,最终出现在shared库 libB.so (因此 libA 必须链接到 libB)。最后我有一个 main 函数也直接从 A 访问静态变量and对 lib 有依赖性(所以我链接到 librARYand libB).

然后我观察到,静态变量被初始化了两次,即它的构造函数运行了两次!这似乎不对。链接器不应该识别两个变量相同并将它们作为一个优化吗?

为了让我的困惑更加完美,我看到它使用相同的地址运行了两次!所以也许链接器did认识它,但是did not删除 static_initialization_and_destruction 代码中的第二个调用?

这是一个展示:

A类.hpp:

#ifndef CLASSA_HPP
#define CLASSA_HPP

class ClassA
{
public:
    ClassA();
    ~ClassA();
    static ClassA staticA;

    void test();
};

#endif // CLASSA_HPP

A类.cpp:

#include <cstdio>
#include "ClassA.hpp"

ClassA ClassA::staticA;

ClassA::ClassA()
{
    printf("ClassA::ClassA() this=%p\n", this);
}

ClassA::~ClassA()
{
    printf("ClassA::~ClassA() this=%p\n", this);
}

void ClassA::test()
{
    printf("ClassA::test() this=%p\n", this);
}

B类.hpp:

#ifndef CLASSB_HPP
#define CLASSB_HPP

class ClassB
{
public:
    ClassB();
    ~ClassB();

    void test();
};

#endif // CLASSB_HPP

B类.cpp:

 #include <cstdio>
 #include "ClassA.hpp"
 #include "ClassB.hpp"

 ClassB::ClassB()
 {
     printf("ClassB::ClassB() this=%p\n", this);
 }

 ClassB::~ClassB()
 {
     printf("ClassB::~ClassB() this=%p\n", this);
 }

 void ClassB::test()
 {
     printf("ClassB::test() this=%p\n", this);
     printf("ClassB::test: call staticA.test()\n");
     ClassA::staticA.test();
 }

测试.cpp:

#include <cstdio>
#include "ClassA.hpp"
#include "ClassB.hpp"

int main(int argc, char * argv[])
{
    printf("main()\n");
    ClassA::staticA.test();
    ClassB b;
    b.test();
    printf("main: END\n");

    return 0;
}

然后我编译并链接如下:

g++ -c ClassA.cpp
ar rvs libA.a ClassA.o
g++ -c ClassB.cpp
g++ -shared -o libB.so ClassB.o libA.a
g++ -c Test.cpp
g++ -o test Test.cpp libA.a libB.so

输出是:

ClassA::ClassA() this=0x804a040
ClassA::ClassA() this=0x804a040
main()
ClassA::test() this=0x804a040
ClassB::ClassB() this=0xbfcb064f
ClassB::test() this=0xbfcb064f
ClassB::test: call staticA.test()
ClassA::test() this=0x804a040
main: END
ClassB::~ClassB() this=0xbfcb064f
ClassA::~ClassA() this=0x804a040
ClassA::~ClassA() this=0x804a040

有人可以解释一下这是怎么回事吗?链接器在做什么?怎样才能same变量被初始化两次?


你包括libA.a into libB.so。通过这样做,双方libB.so and libA.a包含ClassA.o,它定义静态成员。

按照您指定的链接顺序,链接器引入ClassA.o从静态库libA.a, so ClassA.o初始化代码之前运行main()。当第一个函数处于动态状态时libB.so被访问,all初始化程序libB.so正在运行。自从libB.so包括ClassA.o, ClassA.o的静态初始化程序必须(再次)运行。

可能的修复:

  1. 不要将 ClassA.o 同时放入 libA.a 和 libB.so 中。

    g++ -shared -o libB.so ClassB.o
    
  2. 不要同时使用这两个库;不需要 libA.a。

    g++ -o test Test.cpp libB.so
    

应用上述任一方法可以解决问题:

ClassA::ClassA() this=0x600e58
main()
ClassA::test() this=0x600e58
ClassB::ClassB() this=0x7fff1a69f0cf
ClassB::test() this=0x7fff1a69f0cf
ClassB::test: call staticA.test()
ClassA::test() this=0x600e58
main: END
ClassB::~ClassB() this=0x7fff1a69f0cf
ClassA::~ClassA() this=0x600e58
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

静态变量被初始化两次 的相关文章

随机推荐

  • 在 Selenium Chrome 驱动程序中禁用缓存

    我使用 Selenium ChromeDriver 来测量网页的性能 但默认情况下 Chrome 驱动程序缓存是启用的 Option disable application cache现已弃用https code google com p
  • std::mutex 作为类成员,并将类对象存储到容器中

    下面是重现该错误的最少代码 include
  • Powershell:查找/替换 ASCII 控制字符的模式

    我正在尝试编写一个脚本来搜索文件的内容 并在遇到一组 ASCII 控制字符时插入 CR LF 我想替换的字符模式是 ETX NUL STX ETX SOH filenames Get Childitem E VendorFiles CR c
  • Resharper 8.1 测试运行器减慢 Visual Studio 文本编辑速度

    我有一个相当小的 C 解决方案 其中包含大约 5 个项目 我正在使用带有 Update 4 的 Visual Studio 2012 和 Resharper 8 1 内部版本 8 1 23 546 它采用配备 SSD 和 16GB RAM
  • Ruby on Rails 多态关系的优点和缺点 [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 您知道 Ruby on Rails 多态关系有哪些优点和缺点 优点 您可以轻松地将任何东西链接到任何东西 适应性强的关系有助于适应不可预见的情况 很容易建立关系 非常适合临时系统
  • 如何使用 from_json 和 schema 作为字符串(即 JSON 编码的 schema)?

    我正在从 Kafka 读取一个流 并将 Kafka 的值 即 JSON 转换为 Structure from json有一个采用类型模式的变体String 但我找不到样本 请指出下面的代码有什么问题 Error Exception in t
  • Jboss 在根上下文中部署

    是的 我知道enable welcome root false 但在文件中找不到这个 使用 Wildfly Final 或 jboss eap 6 2 在哪儿 为什么我需要在 WEB INF 中添加 jboss web xml 有问题的文件
  • “@Transactional”应该放在服务层或 DAO 的哪里

    首先 我可能正在问一些以前被问过并回答过的问题 但我无法返回搜索结果 我们在服务层定义事务注释 典型的 Spring Hibernate CRUD 通常是 控制器 gt 管理器 gt Dao gt Orm 我现在遇到的情况是 我需要根据客户
  • 在谷歌地图android上实现落针动画

    我正在我的 Android 应用程序中实现谷歌地图 在此过程中我想添加落针动画 我已经搜索了所有内容 但找不到执行此操作的确切方法 任何人都可以帮助我如何做 这将是一个很大的帮助 将标记添加到地图中的所需位置 然后使用该标记调用此函数 pr
  • Python - PyQt - QTable Widget - 添加行

    我是 PyQt 的新手 无论如何仍然有点困惑 我有一个像这样的文本文件结构 姓名 姓氏 电话 电子邮件 空格实际上是制表符 t 现在当我用我的方法读取这个文件时 我希望填充 QTableWidget 我的 QTable Widget 有 4
  • C Int 和 Long 32 - 64 位中的值范围

    我对 C 中 Int 变量的值范围感到困惑 我知道 32 位 unsigned int 的范围是 0 到 65 535 那么只要有0到4 294 967 295 这在 32 位机器上没问题 但现在在 64 位机器中一切都保持不变吗 或者也许
  • 连接两个 gatsby 节点

    所以 我正在使用盖茨比 mdx用于从 MDX 文件创建站点的插件 我想在 SitePage 对象和 Mdx 对象之间创建关联 以便我可以对 SitePage 边缘执行一个 graphQL 查询来构建站点导航 我的大部分代码都是用 TypeS
  • 如何链接没有字幕的 YouTube 视频?

    可以链接吗youtubeHTML 代码中的视频不显示其字幕 字幕 假设我有以下视频 http www youtube com watch v kTvHIDKLFqc 它有默认的英文字幕 但是 当链接该视频时 我想在没有它们的情况下加载它 是
  • C++ 中正态分布的随机数

    作为 C 的完全初学者 我想从正态分布生成一个随机数 使用以下代码 源自此post 我能够这样做 include
  • 我可以在 Windows 7 上使用 C# .NET 开发 Blackberry 应用程序吗

    嘿 我非常有兴趣为黑莓操作系统构建一个应用程序 我可以用 C 来做吗 Blackberry 还推出了 Visual Studio 插件 但您将如何将其与模拟器一起使用 不 你做不到 你必须使用Java来做黑莓开发 黑莓曾经有一个 C C A
  • 使用 ggplot2 以粗体显示各个轴标签

    改编自这个问题和解决方案的问题 使用 ggplot2 以粗体突出显示各个轴标签 我想根据满足标准有选择地证明水平轴标签的合理性 因此 借用上述问题和答案 我设置了一个示例 require ggplot2 require dplyr set
  • 如何在 CSS 中用 div 制作尖箭头

    如何在 CSS 中制作尖箭头 不只是一个三角形 而是一个有茎的三角形 就像用弓射出的传统箭一样 我试图通过创建一个 div 容器来做到这一点 其中包含两个容器 左容器和右容器 右侧将包含三角形 左侧将包含三个 div 其中心将被着色以创建主
  • AdMob 在 Android 中需要哪些权限

    On 谷歌的网站他们只提到其中两个
  • 记录 Excel 自动完成的 VBA 代码

    使用VBA编写要在Excel中使用的自定义函数时 如何编写文档注释以便在自动填充公式期间自动显示Excel 例如 当我们开始输入 VLookUp 时 它会显示 Vlookup 作为工具提示的作用 显示输入变量名称 如果我们按功能区中的 插入
  • 静态变量被初始化两次

    考虑我在编译单元中有一个静态变量 它最终出现在static库 libA 然后我有另一个编译单元访问这个变量 最终出现在shared库 libB so 因此 libA 必须链接到 libB 最后我有一个 main 函数也直接从 A 访问静态变