文章

cpp-设计模式之单例模式

cpp-设计模式之单例模式

设计模式之单例模式

单例模式简介

单例模式是最简单的模式之一,其目的为保证一个类只有一个实例,并提供一个访问它的全局节点.

懒汉式(Lazy Singleton)

懒汉式是最基本的单例模式,单例实例会在第一次被使用时才进行初始化,称之为延迟初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>

class Singleton{
    public:
    static Singleton * getInstance(){
        if(pInstance == nullptr){
            pInstance = new Singleton();
            std::cout << "创建唯一实例" << std::endl;
        }
        return pInstance;
    };

    private:
    Singleton(){}; //构造函数设计成私有的
    static Singleton* pInstance;
};
Singleton* Singleton::pInstance = nullptr;
int main()
{

    Singleton* obj = Singleton::getInstance();
    return 0;
}

懒汉式会存在问题:

  • 线程不安全的问题. 比如两个线程同时调用了 getInstance,恰巧此时 pInstance 都为 nullptr,那么就会调用两次 new,最简单的方法是加锁

  • 存在内存泄漏问题. 有两种解决方法,一种是使用共享指针,另外一种是使用静态的嵌套类对象

改进版懒汉式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <memory>
#include <mutex>

class Singleton{
    public:
    static std::shared_ptr<Singleton> getInstance(){
        if(pInstance == nullptr){
            // doble checked lock
            std::lock_guard<std::mutex> lock(mutex);
            if(pInstance == nullptr){
                // pInstance = new Singleton();
                pInstance = std::shared_ptr<Singleton>(new Singleton);
                std::cout << "创建唯一实例" << std::endl;
            }
        }
        return pInstance;
    };

    private:
    Singleton(){}; //构造函数设计成私有的
    static std::mutex mutex;
    static std::shared_ptr<Singleton> pInstance;
};
std::shared_ptr<Singleton> Singleton::pInstance = nullptr;
std::mutex Singleton::mutex;
int main()
{

    std::shared_ptr<Singleton> obj = Singleton::getInstance();
    return 0;
}

其优点是使用 shared_ptr,基于 RAII 思想用对象管理资源,当 shared_ptr 析构时,new 出来的对象也会被析构掉。 双检锁,double check,使用锁保证线程安全,双检:保证只有当智能指针为空的时候,才会加锁检查,避免每次调用 getInstance 的方法都加锁,浪费锁的开销

另外还可以使用 magic static,局部静态变量,这是最推荐的懒汉式实现方法,其思想主要是利用 c++11 的 static 个性,当变量在初始化的时候,并发同时进入声明语句,并发线程将会阻塞等待初始化结束,这就保证了并发线程 在获取静态局部变量的时候一定是初始化过的,所以具有线程安全性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <memory>
#include <mutex>

class Singleton{
    public:
    static Singleton& getInstance(){
        static Singleton pInstance;
        return pInstance;
    };

    private:
    Singleton(){
        std::cout << "创建单例模式" << std::endl;
    }; //构造函数设计成私有的

};

int main()
{

    Singleton obj = Singleton::getInstance();
    return 0;
}

饿汉式(Eager Singleton)

饿汉式是指单例实例在程序运行时就被立即执行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <memory>
#include <mutex>

class Singleton{
    public:
    static Singleton& getInstance(){
        return pInstance;
    };

    private:
    Singleton(){
        std::cout << "创建单例模式" << std::endl;
    }; //构造函数设计成私有的

    static Singleton pInstance;
};

Singleton Singleton::pInstance;

int main()
{

    Singleton obj = Singleton::getInstance();
    return 0;
}

参考链接:https://www.jianshu.com/p/b71b26c5165b

本文由作者按照 CC BY 4.0 进行授权