You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 01:50:14