C++设计模式——单例模式

单例模式


方法1:C++11 线程不安全懒汉模式(不推荐)

懒汉式单例模式在第一次使用时才创建实例,但这种方式在多线程环境下可能会出现问题。

cpp 复制代码
class Singleton {
private:
    static Singleton* instance; // 静态指针,用于存储单例对象
    Singleton() {} // 私有构造函数,防止外部直接构造

public:
    static Singleton* getInstance() {
        if (instance == nullptr) { // 检查是否已经创建了实例
            instance = new Singleton();
        }
        return instance;
    }
};

// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    // s1 和 s2 指向同一个对象
    return 0;
}

方法2:懒汉式单例模式(线程安全)

为了确保线程安全,可以在getInstance函数中使用互斥锁(std::mutex)

cpp 复制代码
#include <mutex>

class Singleton {
private:
    static Singleton* instance; // 静态指针,用于存储单例对象
    static std::mutex mutex_; // 互斥锁
    Singleton() {} // 私有构造函数,防止外部直接构造

public:
    static Singleton* getInstance() {
        std::lock_guard<std::mutex> lock(mutex_); // 加锁
        if (instance == nullptr) { // 检查是否已经创建了实例
            instance = new Singleton();
        }
        return instance;
    }
};

// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex_;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    // s1 和 s2 指向同一个对象
    return 0;
}

方法3:C++11 基于局部静态变量的单例模式

利用 C++11 的 static 特性实现线程安全的延迟初始化:

cpp 复制代码
class Singleton {
public:
    // 删除拷贝构造和赋值运算符
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    // 全局访问点
    static Singleton& getInstance() {
        static Singleton instance; // C++11保证线程安全的静态局部变量初始化
        return instance;
    }

private:
    Singleton() {}                  // 私有构造函数
    ~Singleton() {}                 // 私有析构函数
};

// 使用示例:
Singleton& obj = Singleton::getInstance();

优点

  • 线程安全(C++11标准保证)
  • 延迟初始化(首次调用时创建)
  • 代码简洁

方法4:双重检查锁定(传统线程安全)

适用于 C++11 之前的版本:

cpp 复制代码
#include <mutex>
#include <atomic>

class Singleton {
public:
    static Singleton* getInstance() {
        Singleton* tmp = instance.load(std::memory_order_acquire);
        if (tmp == nullptr) {                     // 第一次检查
            std::lock_guard<std::mutex> lock(mutex);
            tmp = instance.load(std::memory_order_relaxed);
            if (tmp == nullptr) {                 // 第二次检查
                tmp = new Singleton();
                instance.store(tmp, std::memory_order_release);
            }
        }
        return tmp;
    }

    // 删除拷贝和赋值
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

private:
    Singleton() {}                                // 私有构造函数
    ~Singleton() {}                               // 私有析构函数
    static std::atomic<Singleton*> instance;      // 原子指针
    static std::mutex mutex;                      // 互斥锁
};

// 初始化静态成员
std::atomic<Singleton*> Singleton::instance{nullptr};
std::mutex Singleton::mutex;

// 使用示例:
Singleton* obj = Singleton::getInstance();

优点

  • 线程安全
  • 延迟初始化
  • 高性能(避免每次调用加锁)

方法5:饿汉模式(程序启动时初始化)

线程安全但提前初始化:

cpp 复制代码
class Singleton {
public:
    static Singleton& getInstance() {
        return instance; // 直接返回已初始化的实例
    }

    // 删除拷贝和赋值
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

private:
    Singleton() {}                                // 私有构造函数
    ~Singleton() {}                               // 私有析构函数
    static Singleton instance;                   // 程序启动时初始化
};

// 初始化静态成员(在.cpp文件中)
Singleton Singleton::instance;

// 使用示例:
Singleton& obj = Singleton::getInstance();

优点

  • 线程安全
  • 实现简单

缺点

  • 程序启动时即初始化,可能浪费资源
  • 无法处理依赖其他模块初始化的情况

单例模式的关键点

  1. 构造函数私有化:禁止外部创建实例
  2. 删除拷贝和赋值:防止通过拷贝创建新对象
  3. 全局访问点:静态方法提供唯一访问入口
  4. 线程安全:根据场景选择实现方式

注意事项

  • 避免滥用单例模式(可能导致代码耦合度高)
  • 单例对象的销毁需要谨慎处理(一般程序结束时自动释放)
  • 多线程环境下优先使用 C++11 的 static 实现
相关推荐
王老师青少年编程12 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮13 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
样例过了就是过了14 小时前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
谭欣辰14 小时前
C++ 排列组合完整指南
开发语言·c++·算法
橙子也要努力变强15 小时前
信号捕捉底层机制-机理篇2
linux·服务器·c++
盐焗鹌鹑蛋15 小时前
【C++】stack和queue类
c++
郝学胜-神的一滴16 小时前
罗德里格斯旋转公式(Rodrigues‘ Rotation Formula)完整推导
c++·unity·godot·图形渲染·three.js·unreal
lzh2004091916 小时前
深入理解进程:从PCB内核结构到写时拷贝的底层实战
linux·c++
aseity17 小时前
跨平台项目中QString 与 非Qt 跨平台动态库在字符集上的一个实用的互操作约定.
c++·经验分享
CN-Dust17 小时前
【C++】while语句例题专题
数据结构·c++·算法