C++ .so动态库静态对象未共享问题:为何单例实例被重复创建?
问题:共享库中的静态内存空间为何未在模块间共享?
项目依赖与现象
- Package1.so:提供单例类
A,其get_instance()方法通过静态智能指针实现懒加载,并用静态互斥锁保证线程安全。 - Package2:依赖Package1.so,调用
A::get_instance()获取实例。 - Package3:依赖Package1.so和Package2,同样直接调用
A::get_instance()。
预期:单例对象仅创建一次,在Package2和Package3间共享。
实际:对象被创建了两次,两个模块拿到的是不同实例。
代码示例
// Package1 - h1.hpp #pragma once #include <memory> #include <mutex> class A { public: static std::shared_ptr<A> get_instance(); private: static std::mutex m_mtx; static std::shared_ptr<A> m_instance; };
// Package1 - h1.cpp #include "h1.hpp" // 错误:此处用static修饰类静态成员 static std::mutex A::m_mtx; static std::shared_ptr<A> A::m_instance; std::shared_ptr<A> A::get_instance() { const std::lock_guard<std::mutex> lck{m_mtx}; // 修正原代码括号笔误 if (nullptr == m_instance) { m_instance = std::make_shared<A>(); } return m_instance; }
// Package2 代码 #include <path/h1.hpp> void f() { auto instance = A::get_instance(); // 首次调用创建实例 }
// Package3 代码 #include <path/h1.hpp> void g() { auto instance = A::get_instance(); // 首次调用再次创建实例 }
原因分析与解决方案
核心问题:错误使用static修饰类静态成员
类的静态成员本身属于外部链接,可在多个编译单元间共享,但你在Package1的h1.cpp中用static修饰了A::m_mtx和A::m_instance的定义,强行将它们的链接属性改为内部链接。
内部链接意味着:每个依赖Package1的模块(Package2、Package3)都会在自身地址空间中创建一份这些静态变量的独立副本。Package2调用get_instance()时初始化的是自己副本里的m_instance,Package3调用时初始化的是另一个副本,最终导致两个独立的单例对象。
解决方案
去掉h1.cpp中类静态成员定义前的static关键字即可:
// Package1 - h1.cpp 修正后 #include "h1.hpp" std::mutex A::m_mtx; std::shared_ptr<A> A::m_instance; std::shared_ptr<A> A::get_instance() { const std::lock_guard<std::mutex> lck{m_mtx}; if (nullptr == m_instance) { m_instance = std::make_shared<A>(); } return m_instance; }
关于共享库静态内存的说明
正常情况下,共享库(.so)中的外部链接静态/全局变量在进程地址空间中只会存在一份,所有依赖该库的模块都会共享这一份内存。但如果变量被标记为内部链接(用static修饰或匿名命名空间包裹),则每个依赖模块都会拥有独立的副本,无法实现跨模块共享。
内容的提问来源于stack exchange,提问作者Martin Ayvazyan
相关产品推荐
相关产品推荐

