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

如何构造多个单例对象?参数化单例调用返回同一实例问题排查与解决

问题原因分析

你遇到的问题核心在于C++函数内静态变量的初始化规则:函数级别的静态变量,会在第一次进入该函数时完成初始化,之后无论你调用多少次这个函数、传入什么参数,这个静态变量都只会存在一份,不会重新创建。

具体到你的代码,static A u(i);是定义在Inst(int i)函数内部的静态变量:

  • 第一次调用Inst(1)时,程序进入函数,初始化u为A(1),之后这个u就一直存在于程序的整个生命周期;
  • 当你调用Inst(2)时,函数再次被执行,但静态变量u已经初始化过了,所以不会再执行A(2)的构造,直接返回已经存在的u(也就是之前创建的no_=1的实例)。

这就是为什么b和c会共享同一个实例的原因。

解决方案:用容器映射参数到实例

要实现「每个参数对应一个唯一实例」的需求,我们可以用一个静态容器(比如std::unordered_map)来存储不同参数对应的实例,让每个参数值对应一个独立的对象。

基础实现版本

#include <bits/stdc++.h>
#include <unordered_map>
#include <memory>

class A {
private:
    A() { printf("init a unparam A\n"); }
    A(int i) : no_(i) { printf("init a A with no = %d\n", no_); }
    virtual ~A() = default;

    // 禁用拷贝构造和赋值运算符,避免实例被意外复制
    A(const A&) = delete;
    A& operator=(const A&) = delete;

    // 静态容器:存储参数到实例的映射
    static std::unordered_map<int, std::unique_ptr<A>> instances_;

public:
    static A& Inst() {
        static A u;
        return u;
    }

    static A& Inst(int i) {
        auto it = instances_.find(i);
        if (it == instances_.end()) {
            // 如果不存在对应参数的实例,创建并插入容器
            instances_[i] = std::make_unique<A>(i);
        }
        // 返回对应参数的实例引用
        return *instances_[i];
    }

    void print() { printf("my no = %d\n", no_); }
    int no_;
};

// 静态成员必须在类外部初始化
std::unordered_map<int, std::unique_ptr<A>> A::instances_;

测试运行结果

当你运行原来的main函数时,输出会符合你的预期:

init a unparam A
my no = 0
init a A with no = 1
my no = 1
init a A with no = 2
my no = 2

线程安全优化(可选)

如果你的程序是多线程环境,上面的基础版可能会出现竞争条件(比如多个线程同时调用Inst(i)且该参数的实例尚未创建时,可能会重复创建)。这时可以加上互斥锁保证线程安全:

#include <mutex>

class A {
private:
    // ... 其他成员不变
    static std::mutex mutex_; // 新增互斥锁

public:
    static A& Inst(int i) {
        // 加锁确保同一时间只有一个线程能修改容器
        std::lock_guard<std::mutex> lock(mutex_);
        auto it = instances_.find(i);
        if (it == instances_.end()) {
            instances_[i] = std::make_unique<A>(i);
        }
        return *instances_[i];
    }
    // ...
};

// 初始化互斥锁
std::mutex A::mutex_;

总结

  • 函数内的静态变量是函数级别的单例,与传入的参数无关,只会初始化一次;
  • 要实现「参数化单例」,需要用容器来维护参数和实例的映射关系;
  • 记得禁用拷贝构造和赋值运算符,防止实例被意外复制;
  • 多线程场景下需要添加互斥锁保证线程安全。

内容的提问来源于stack exchange,提问作者nick

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 06:49:51