设计模式-单例模式1(基本使用)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010021282/article/details/54234562

  单例模式是23种设计模式中最简单,同时也是最常使用到的一种设计模式,它的特点是一个对象只会有一个实例被创建。

  比如,在实际程序开发中,程序启动往往需要把配置文件的信息加载到一个类里面。我们希望这个类不被多次实例化,且能够被全局访问,这时候就可以将这个类设计成单例。


一个单例类,应当拥有以下成员:
1、一个静态私有变量或指针,指向自身
2、一个静态公有方法,用于获取类的唯一实例
3、私有的构造函数、拷贝构造函数、类赋值函数,保证不会在类外实例化

先来看看饿汉式和懒汉式的基本实现:

饿汉式:

class CSingleton
{

public:
    virtual ~CSingleton(void){};
public:
    static CSingleton* GetInstance();
private:
    CSingleton(void){};
    CSingleton(const CSingleton&);//不需要实现
    CSingleton operator = (const CSingleton&);//不需要实现
private:
    static CSingleton   m_objInstance; //唯一实例
};


CSingleton CSingleton::m_objInstance;
CSingleton* CSingleton::GetInstance()
{
    return &m_objInstance;
}

懒汉式:

class CSingleton
{

public:
    virtual ~CSingleton(void){};
public:
    static CSingleton* GetInstance();

private:
    CSingleton(void){};
    CSingleton(const CSingleton&);//不需要实现
    CSingleton operator = (const CSingleton&);//不需要实现
private:
    static CSingleton*  m_pInstance;//唯一实例
};


CSingleton* CSingleton::m_pInstance=NULL;
CSingleton* CSingleton::GetInstance()
{
    if (m_pInstance==NULL)
    {
        m_pInstance=new CSingleton();
    }
    return m_pInstance;
}

饿汉式跟懒汉式的区别就在实例化的时机不一样,懒汉式在第一次使用GetInstance获取实例的时候实例化,而饿汉式一开始就创建实例。

内存泄漏问题:

C++没有垃圾回收机制,若使用上面的饿汉式单例,由于m_pInstance得不到释放,将会造成内存泄漏!

这里我打算使用的智能指针share_ptr自动管理实例的内存,当程序结束时,自动释放m_pInstance:

#include "memory"  //share_ptr头文件

class CSingleton;
typedef std::shared_ptr<CSingleton>  Singleton_ptr;
class CSingleton
{

public:
    virtual ~CSingleton(void) {};
public:
    static CSingleton* GetInstance();
private:
    CSingleton(void) {};
    CSingleton(const CSingleton&);//不需要实现
    CSingleton operator = (const CSingleton&);//不需要实现
private:
    static Singleton_ptr    m_pInstance;//唯一实例
};

Singleton_ptr CSingleton::m_pInstance;
CSingleton* CSingleton::GetInstance()
{
    if (m_pInstance == NULL)
    {
        m_pInstance = Singleton_ptr(new CSingleton());
    }
    return m_pInstance.get();
}

当程序退出时,如果已经实例化,智能指针自动释放内存。

线程安全考虑:
内存泄漏的问题解决了,但是当多线程同时获取实例,还是可能会出现不可预期的异常,也就是线程安全问题仍未解决。

如果要保证线程安全,就必须上锁:

#include <mutex>
#include <memory>
class CSingleton;
typedef std::shared_ptr<CSingleton>  Singleton_ptr;
class CSingleton
{

public:
    virtual ~CSingleton(void) {};
public:
    static CSingleton* GetInstance();
private:
    CSingleton(void) {};
    CSingleton(const CSingleton&);//不需要实现
    CSingleton operator = (const CSingleton&);//不需要实现
private:
    static Singleton_ptr    m_pInstance;//唯一实例
    static std::mutex        m_mutex;
};

Singleton_ptr CSingleton::m_pInstance;
std::mutex  CSingleton::m_mutex;
CSingleton* CSingleton::GetInstance()
{
    if (m_pInstance == NULL)//1 判断指针是否为空
    {
        std::unique_lock<std::mutex>  lk(m_mutex);//此处上锁
        if (m_pInstance == NULL)//2 再次判断
        {
            m_pInstance = Singleton_ptr(new CSingleton());
        }

    }
    return m_pInstance.get();
}

里面对m_pInstance作了两次判断,两次都是必要的:
若去掉判断1,程序不会出问题,但是效率会下降,因为每次获取实例都会加锁。
若去掉判断2,则有可能会出现被多次实例的可能,那就失去上锁的意义了。

猜你喜欢

转载自blog.csdn.net/u010021282/article/details/54234562