基于C++的单例模式

单例模式是一种设计模式.
单例模式表示在定义的某一个类中,只能有唯一的一个对象(即只能有一个实例).
优点:提高了封装性,外部不能轻易的改变实例.

饿汉模式

含义:程序启动后就会立即加载到内存.
缺点:启动比较慢.
代码如下:

#include <iostream>
using namespace std;

template<class T>
class Singleton
{
public:
    static T* GetSingleton()
    {
        return &value;
    }
private:
    static T value;
};
template<class T>
T Singleton<T>::value = T();

int main()
{
    Singleton<int>::GetSingleton();
    return 0;
}

懒汉模式

含义:启动的时候不加载,只有当使用的时候才会加载到内存.

#include <iostream>
using namespace std;

//懒汉模式
template<class T>   //类模板
class singleton
{
public:
    static T* GetSingleton()
    {
        if(value == NULL)
        {
            value = new T();
        }
        return value;
    }
private:
    static T* value;
};
template<class T>
T* singleton<T>::value = NULL;

int main()
{
    singleton<int>::GetSingleton();
    return 0;
}

上面这个代码存在一个很重要的问题:

1.如果在多线程的环境下,在函数GetSingleton()中如果进行判断时如果同时多个线程频繁的进行判断,那么就会存在线程安全问题,如果多个线程都判断为空那么就会new出来很多对象,那么明显就是不安全的.
解决:加锁,在判断前进行加锁,在出了if判断再进行解锁.
问题:如果有多个进程频繁的获取锁,然后再进行判断,然后再释放.那么效率就会下降,加锁和解锁也是一种消耗.
解决:在加锁前再进行一次判断,如果为空才进行进行加锁.这样就会大大减少了加解锁的消耗.

具体的代码如下:
template<class T>
class singleton
{
public:
    static T* GetSingleton()
    {
        if(value == NULL)    //这样就只有为空才会进来进行加锁解锁(这样就不会频繁获取锁)
        {
            lock(); //这是一句伪代码(加锁)
            //如果在这儿加锁,所有的线程到这儿都会先加锁(这也是一种消耗),再判断,这样就会造成效率低.所以在这儿之前再进行一次判断
            //但是在这儿加锁也会满足线程安全
            if(value == NULL)
            {
                value = new T();
            }
            unlock();  //伪代码(解锁)
        }
        return value;
    }
private:
    static volatile  T* value;  //加上volatile为了防止编译器过度优化
};
template<class T>
volatile T* singleton<T>::value = NULL;

猜你喜欢

转载自blog.csdn.net/yinghuhu333333/article/details/80783603