单例模式

文章目录

一、要点

0.单例模式,顾名思义只能有一个实例对象

1.私有化构造函数 :不能随便调用构造函数来实例化对象

2.删除拷贝构造函数、赋值运算符函数 :确保唯一实例

3.使用静态成员变量,存储指向单例对象的指针 :静态方法属于类,不属于具体的实例对象。

4.提供静态方法,在堆上获取单例对象

二、代码

延迟实例化、懒加载、懒汉式:实例在第一次使用时才会被创建

1.核心代码

cpp 复制代码
static Singleton* getInstance() {
    if (instance == nullptr) {
        instance = new Singleton();  // 只有在第一次调用时创建实例
    }
    return instance;
}

2.详细注释代码

cpp 复制代码
#include <iostream> 
using std::cout;
using std::endl;

//单例模式:要通过给的接口来创造唯一实例。
//因此,要将构造函数私有化,并且删除拷贝构造和赋值运算符函数

class Singleton
{
public:
    //静态方法,用于获取唯一的实例。静态方法属于类,而非实例对象
    //懒加载、懒汉式、延迟实例化
    static Singleton* getInstance()
    {
        if(pInstance == nullptr){
            pInstance = new Singleton(); 
        }
        return pInstance;
    }

    void display()
    {
        cout << "This is the Singleton instance." << "\n";
    }
private:
    //构造函数私有化,防止外部创建对象
    Singleton()
    {
        cout << "Singleton instance created.\n";
    }

    //禁用拷贝构造和赋值运算符函数
    Singleton(const Singleton & ) = delete;
    Singleton & operator=(const Singleton &) = delete;

    //静态成员变量,存储唯一的实例
    static Singleton* pInstance;
};

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

int main()
{
    //获取单例对象的唯一实例
    Singleton* s1 = Singleton::getInstance();
    s1->display();

    //再次获取单例对象的实例
    Singleton* s2 = Singleton::getInstance();
    s2->display();

    //验证两个指针是否指向同一个实例
    if(s1 == s2){
        cout << "Both pointer point to the same instance.\n";
    }

    return 0;
}

另一版

cpp 复制代码
#include <iostream> 
using std::cout;
using std::endl;

//单例模式:要通过给的接口来创造唯一实例。
//因此,要将构造函数私有化,并且删除拷贝构造和赋值运算符函数

class Singleton
{
private:
    //构造函数私有化,防止外部创建对象
    Singleton()
    {
        cout << "Singleton instance created.\n";
    }

    //禁用拷贝构造和赋值运算符函数
    Singleton(const Singleton & ) = delete;
    Singleton & operator=(const Singleton &) = delete;

    //静态成员变量,存储唯一的实例
    static Singleton* instance;
public:
    //静态方法,用于获取唯一的实例
    static Singleton* getInstance()
    {
        if(instance == nullptr){
            instance = new Singleton(); //延迟实例化
        }
        return instance;
    }

    void display()
    {
        cout << "This is the Singleton instance." << "\n";
    }
};

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

int main()
{
    //获取单例对象的唯一实例
    Singleton* s1 = Singleton::getInstance();
    s1->display();

    //再次获取单例对象的实例
    Singleton* s2 = Singleton::getInstance();
    s2->display();

    //验证两个指针是否指向同一个实例
    if(s1 == s2){
        cout << "Both pointer point to the same instance.\n";
    }

    return 0;
}

3.无注释代码 (单线程时,存在线程安全问题)

cpp 复制代码
#include <iostream> 
using std::cout;
using std::endl;

class Singleton
{
public:
    static Singleton* getInstance()
    {
        if(pInstance == nullptr){
            pInstance = new Singleton();
        }
        return pInstance;
    }

private:
    Singleton(){};
    Singleton(const Singleton & rhs) = delete;
    Singleton & operator= (const Singleton & rhs) = delete;
    static Singleton* pInstance;
};

Singleton* Singleton::pInstance = nullptr;

int main()
{
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    if(s1 == s2){
        cout << "s1 == s2,是单例的\n";
    }else{
        cout << "s1 != s2,不是单例的\n";
    }

    return 0;
}

4.考虑线程安全 (getInstance加锁)

cpp 复制代码
#include <iostream> 
#include <mutex>
using std::cout;
using std::mutex;
using std::lock_guard;

class Singleton
{
public:
    static Singleton* getInstance()
    {
        lock_guard<mutex> lock(mtx);
        if(pInstance == nullptr){
            pInstance = new Singleton();
        }
        return pInstance;
    }

private:
    Singleton(){};
    Singleton(const Singleton & rhs) = delete;
    Singleton & operator= (const Singleton & rhs) = delete;
    static Singleton* pInstance;
    static mutex mtx; //互斥锁,确保线程安全
};

Singleton* Singleton::pInstance = nullptr;
mutex Singleton::mtx;

int main()
{
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    if(s1 == s2){
        cout << "s1 == s2,是单例的\n";
    }else{
        cout << "s1 != s2,不是单例的\n";
    }

    return 0;
}
4.1 进一步减少加锁的开销,使用双重检查锁
cpp 复制代码
// 线程安全的 getInstance 方法,使用双重检查锁
static Singleton* getInstance()
{
    if(pInstance == nullptr) {  // 第一次检查,无锁
        std::lock_guard<std::mutex> lock(mtx);  // 加锁
        if(pInstance == nullptr) {  // 第二次检查,加锁后
            pInstance = new Singleton();
        }
    }
    return pInstance;
}

5.释放单例资源以避免内存泄露(智能指针)

cpp 复制代码
#include <iostream> 
#include <mutex>
#include <memory>

using std::cout;
using std::mutex;
using std::lock_guard;
using std::unique_ptr;

class Singleton
{
public:
    static Singleton* getInstance()
    {
        lock_guard<mutex> lock(mtx);
        if(pInstance == nullptr){
            /* pInstance = new Singleton(); */
            pInstance = unique_ptr<Singleton>(new Singleton());
        }
        return pInstance.get();
    }

private:
    Singleton(){};
    Singleton(const Singleton & rhs) = delete;
    Singleton & operator= (const Singleton & rhs) = delete;
    /* static Singleton* pInstance; */
    static unique_ptr<Singleton> pInstance;
    static mutex mtx; //互斥锁,确保线程安全
};

/* Singleton* Singleton::pInstance = nullptr; */
unique_ptr<Singleton> Singleton::pInstance = nullptr;
mutex Singleton::mtx;

int main()
{
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    if(s1 == s2){
        cout << "s1 == s2,是单例的\n";
    }else{
        cout << "s1 != s2,不是单例的\n";
    }

    return 0;
}

6.饿汉式

饿汉式:在类加载时就进行实例化

cpp 复制代码
#include <iostream>
using namespace std;

class Singleton{
public:
    // 提供全局访问点
    static Singleton& getInstance()
    {
        // 静态局部变量在程序启动时初始化
        static Singleton instance;
        return instance;
    }

    // 删除拷贝构造函数和赋值操作符,防止复制
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    // 示例方法
    void display() const{
        cout << "Singleton::display() called on instance: " << this << endl;
    }
private:
    // 私有构造函数
    Singleton(){
        cout << "Singleton()" << endl;
    }
    // 私有析构函数
    ~Singleton(){
        cout << "~Singleton()" << endl;
    }
};

int main()
{
    // 通过getInstance获取单例对象的引用,并调用示例方法
    Singleton& s1 = Singleton::getInstance();
    s1.display();

    // 再次获取单例对象的引用,验证它们是同一个实例
    Singleton& s2 = Singleton::getInstance();
    s2.display();

    // 输出将展示s1和s2有相同的地址,说明它们是同一个实例
    return 0;
}
相关推荐
陈 洪 伟1 天前
C++单例模式代码实现与分析
c++·单例模式
仙魁XAN2 天前
Unity 设计模式 之 创建型模式 -【单例模式】【原型模式】 【建造者模式】
unity·单例模式·设计模式·建造者模式·原型模式
秦淮渔火2 天前
单例模式(饿汉式-懒汉式)
java·开发语言·单例模式
蔚一2 天前
Java设计模式(单例模式)——单例模式存在的问题(完整详解,附有代码+案例)
java·开发语言·单例模式·设计模式
小乖兽技术2 天前
C#开发基础之单例模式下的集合数据,解决并发访问读写冲突的问题
单例模式·c#·线程安全·读写冲突·并发访问
不睡懒觉的橙2 天前
【医疗大数据】基于 B2B 的医疗保健系统中大数据信息管理的安全和隐私问题分析
大数据·安全·单例模式
xiaobai12 32 天前
【C/C++语言系列】实现单例模式
c语言·c++·单例模式
MTingle3 天前
[JavaEE]单例模式(以懒汉模式和饿汉模式为例)
单例模式
我要2003 天前
工厂模式,策略模式,代理模式,单例模式在项目中的应用
单例模式·代理模式·策略模式