当前位置: 首页 > article >正文

C++中如何实现单例模式?

单例模式(Singleton Pattern)是一种设计模式,旨在确保一个类只有一个实例,并提供全局访问点。在 C++ 中实现单例模式有多种方式,下面介绍几种常见的实现方法。

1. 饿汉式(线程安全)

饿汉式是指在程序启动时就创建单例对象。这种方式实现简单,但不适用于创建过程较为复杂的对象。

示例:饿汉式单例模式
#include <iostream>

class Singleton {
private:
    static Singleton instance;  // 声明静态实例

    // 构造函数和拷贝构造函数私有,防止外部创建对象
    Singleton() {
        std::cout << "Singleton instance created!" << std::endl;
    }
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    // 提供公共的静态方法来访问单例
    static Singleton& getInstance() {
        return instance;
    }

    void showMessage() {
        std::cout << "Hello, Singleton!" << std::endl;
    }
};

// 在类外定义静态实例
Singleton Singleton::instance;

int main() {
    Singleton& singleton1 = Singleton::getInstance();
    singleton1.showMessage();

    Singleton& singleton2 = Singleton::getInstance();
    singleton2.showMessage();

    return 0;
}
说明:
  • Singleton 类有一个静态成员 instance,在程序加载时就会创建它。
  • 构造函数、拷贝构造函数和赋值操作符是私有的,因此外部无法直接创建或拷贝 Singleton 对象。
  • getInstance() 提供了唯一的访问点来获取单例对象。

2. 懒汉式(线程不安全)

懒汉式是指在首次使用时才创建单例对象。这个方法的缺点是没有考虑线程安全性,可能在多线程环境下出现问题。

示例:懒汉式单例模式(线程不安全)
#include <iostream>

class Singleton {
private:
    static Singleton* instance;

    // 构造函数和拷贝构造函数私有,防止外部创建对象
    Singleton() {
        std::cout << "Singleton instance created!" << std::endl;
    }
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    // 提供公共的静态方法来访问单例
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }

    void showMessage() {
        std::cout << "Hello, Singleton!" << std::endl;
    }
};

// 静态成员初始化为空指针
Singleton* Singleton::instance = nullptr;

int main() {
    Singleton* singleton1 = Singleton::getInstance();
    singleton1->showMessage();

    Singleton* singleton2 = Singleton::getInstance();
    singleton2->showMessage();

    return 0;
}
说明:
  • instance 是一个静态指针,首次调用 getInstance() 时创建单例对象。
  • 对于多线程程序,这种方式存在风险,因为多个线程可能同时通过 getInstance() 创建多个实例。

3. 线程安全的懒汉式(加锁)

为了确保在多线程环境下,懒汉式单例模式是线程安全的,可以使用互斥锁(mutex)来保证在多线程环境下的安全性。

示例:线程安全的懒汉式单例模式(加锁)
#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;

    // 构造函数和拷贝构造函数私有,防止外部创建对象
    Singleton() {
        std::cout << "Singleton instance created!" << std::endl;
    }
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    // 提供公共的静态方法来访问单例
    static Singleton* getInstance() {
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mtx);  // 加锁,保证线程安全
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }

    void showMessage() {
        std::cout << "Hello, Singleton!" << std::endl;
    }
};

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

int main() {
    Singleton* singleton1 = Singleton::getInstance();
    singleton1->showMessage();

    Singleton* singleton2 = Singleton::getInstance();
    singleton2->showMessage();

    return 0;
}
说明:
  • 通过在 getInstance() 方法中使用 std::mutex 进行加锁,确保在多线程环境下只有一个线程能创建单例对象。
  • 使用双重检查锁定模式:第一次检查 instance == nullptr 是为了避免不必要的加锁,第二次检查是在加锁后进行,确保只会有一个线程创建对象。

4. 使用 std::call_once 实现线程安全的单例模式

C++11 提供了 std::call_oncestd::once_flag,可以在多线程环境下以更加高效的方式实现线程安全的单例模式。

示例:使用 std::call_once 实现线程安全的懒汉式单例
#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::once_flag flag;

    // 构造函数和拷贝构造函数私有,防止外部创建对象
    Singleton() {
        std::cout << "Singleton instance created!" << std::endl;
    }
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    // 提供公共的静态方法来访问单例
    static Singleton* getInstance() {
        std::call_once(flag, []() {
            instance = new Singleton();
        });
        return instance;
    }

    void showMessage() {
        std::cout << "Hello, Singleton!" << std::endl;
    }
};

// 静态成员初始化
Singleton* Singleton::instance = nullptr;
std::once_flag Singleton::flag;

int main() {
    Singleton* singleton1 = Singleton::getInstance();
    singleton1->showMessage();

    Singleton* singleton2 = Singleton::getInstance();
    singleton2->showMessage();

    return 0;
}
说明:
  • std::call_once 保证了某段代码(这里是创建单例对象)在多线程环境下只会执行一次,避免了线程安全的问题。

总结

  • 饿汉式:类加载时即创建单例对象,线程安全,适用于简单对象。
  • 懒汉式(线程不安全):只有在首次使用时才创建对象,不适用于多线程环境。
  • 懒汉式(线程安全):通过互斥锁保证线程安全,但性能较差,适用于多线程环境。
  • std::call_once:通过 std::call_once 实现线程安全且性能较优的懒汉式单例模式。

http://www.kler.cn/a/443533.html

相关文章:

  • 【深度学习基础之多尺度特征提取】多尺度图像增强(Multi-Scale Image Augmentation)是如何在深度学习网络中提取多尺度特征的?附代码
  • 云计算学习架构篇之HTTP协议、Nginx常用模块与Nginx服务实战
  • Springboot使用RabbitMQ实现关闭超时订单的一个简单示例
  • 小程序租赁系统构建指南与市场机会分析
  • C语言宏和结构体的使用代码
  • 【游戏设计原理】41 - 游戏的核心
  • 【Maven】基础(一)
  • 深度神经网络(DNN)在时序预测中的应用与缺陷
  • 前端 计算发布时间(如“1小时前”、“3天前”等)
  • Mybatis plus查询开用了Redis缓存,一开始挺快,用户多/时间拉长就变慢了
  • django基于python的图书馆管理系统
  • 重生之我在异世界学智力题(8)
  • Python中exifread库使用
  • microk8s使用
  • 通过枚举值调用函数
  • 详解CompletableFuture
  • 写SQL太麻烦?免费搭建 Text2SQL 应用,智能写 SQL | OceanBase AI 实践
  • SSM 寝室管理系统:住宿管理的科技之光
  • 腾讯地图+vue实现后台设置某外卖店铺的位置坐标
  • SAP抓取外部https报错SSL handshake处理方法
  • java不用启动项目测试方法
  • Node.js的Web服务在Nacos中的实践
  • Oracle筑基篇-体系结构概览
  • 【开源库 | minizip】Linux(Ubuntu18.04)下,minizip的编译、交叉编译
  • 使用CSS把背景图片铺满屏幕
  • Windows Server 2019 配置PHP环境(图文教程)