C++ 单例模式

本文介绍了C++中的单例模式,这是一种确保全局只有一个实例的设计模式,有助于减少系统开销。单例模式的特点包括全局唯一实例和静态成员函数提供访问。文章详细讨论了如何通过私有构造函数和静态成员实现单例,并提到了线程安全问题及解决策略。此外,还区分了懒汉式和饿汉式的实现,前者在需要时创建对象,后者在类构造时创建。选择哪种方式取决于访问量和性能需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

单例模式是最常用的设计模式之一, 它可以保证系统中只有一个实例,从而避免频繁的创建和销毁对象,减少系统开销


特点

  • 全局只有一个实例,所有模块共享
  • 提供一个全局访问的方法:getInstance(), 静态成员函数
  • 构造函数私有化
  • 内置静自身态成员对象(或指针)

代码实现

#ifndef _SINGLETON_H
#define _SINGLETON_H
class Singleton
{
public:
    static Singleton * getInstance()
    {
        if(m_singleton == nullptr)
        {
           m_singleton = new Singleton();
        }

        return m_singleton;
    }

private:
    Singleton()
    {
    }

private:
    static Singleton *m_singleton;
};

Singleton *Singleton::m_singleton = nullptr;

#endif

注意:

  1. 构造函数私有化,提供静态函数getInstance()来生成对象
  2. 内部包含静态成员,且在类外面初始化(且在该类文件中)

存在风险: 线程不安全

当多线程操作时, 有可能会在执行  if(m_singleton == nullptr)语句时,容易由于临界点问题,导致两个对象产生

解决办法:双重锁定

Singleton* getInstance()
{
    if (instance == NULL)
    {
    lock(); //创建静态mutex,使用局部lock即可
        if (instance == NULL)
        {
            instance = new Singleton();
        }
        unlock();
    }

    return instance;
}

常用的场景

单例模式常常与工厂模式结合使用,因为工厂只需要创建产品实例就可以了,在多线程的环境下也不会造成任何的冲突,因此只需要一个工厂实例就可以了。

类型

  • 懒汉式 : 不到万不得已时不创建对象
  • 恶汉式 : 类构造时就创建(静态函数,在程序一开始运行时即创建,使用时直接返回)

特点与选择

  1. 由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间

  2. 在访问量较小时,采用懒汉实现。这是以时间换空间。

借鉴文章:http://www.cnblogs.com/qiaoconglovelife/p/5851163.html

### C++ 单例设计模式的实现与使用 #### 实现线程安全的懒汉式单例模式 为了确保实例仅被创建一次并提供全局访问点,在C++中可以通过静态成员函数来控制类对象的创建过程。下面展示了一种常见的懒加载方式,即当第一次调用 `getInstance` 方法时才初始化该类的对象[^1]。 ```cpp class Singleton { private: static std::unique_ptr<Singleton> instance; // 私有化构造函数防止外部new Singleton() {} public: ~Singleton() {} // 删除拷贝构造赋值操作符以阻止复制行为 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; // 获取唯一实例的方法, 使用双重检测锁机制保证多线程环境下的安全性 static Singleton* getInstance() { if (instance.get() == nullptr) { // 第一层判断减少竞争开销 std::lock_guard<std::mutex> lock(mutex_); if (!instance) { // 双重检查锁定 instance.reset(new Singleton()); } } return instance.get(); } private: static std::once_flag initFlag; // 初始化标志位 static std::mutex mutex_; // 同步互斥量用于保护临界区 }; std::unique_ptr<Singleton> Singleton::instance(nullptr); std::once_flag Singleton::initFlag; std::mutex Singleton::mutex_; ``` 这种方法不仅实现了延迟加载(Lazy Initialization),还通过双层校验加锁的方式提高了并发性能,适用于高并发场景下资源的竞争管理[^2]。 #### 饿汉式单例模式 如果应用程序启动之初就需要立即获取到这个唯一的实例,则可以采用饿汉式的写法。这种方式非常简单直观,因为实例是在定义的时候就被创建出来的,所以不存在任何同步问题[^3]。 ```cpp class Singleton { private: // 构造器私有化 Singleton() {}; public: // 禁止拷贝 Singleton(Singleton const&) = delete; void operator=(Singleton const&) = delete; // 提供全局访问接口 static Singleton& GetInstance(){ static Singleton instanse; return instanse; } }; // 客户端代码可以直接这样获得单例对象: void someFunction(){ auto &singletonObj = Singleton::GetInstance(); } ``` 此版本利用了局部静态变量特性——它们会在首次执行所在语句之前完成初始化工作,并且整个程序生命周期内只做这一次初始化动作[^4]。 #### 应用场合说明 对于大多数情况而言,推荐优先考虑基于局部静态变量特性的饿汉式方案,除非确实存在明显的按需分配需求或者担心编译期就占用过多内存空间等问题才会转向更复杂的懒加载形式[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值