C++设计模式——单例模式

何为单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点, 该实例被所有程序模块共享。
首先,需要保证一个类只有一个实例;在类中,要构造一个实例,就必须调用类的构造函数,如此,为了防止在外部调用类的构造函数而构造实例,需要将构造函数的访问权限标记为private或者protected;最后,需要提供要给全局访问点,就需要在类中定义一个static函数,返回在类内部唯一构造的实例。

实现方法一:
用户访问唯一实例的方法只有GetInstance()成员函数。如果不通过这个函数,任何创建实例的尝试都将失败,因为类的构造函数是私有的。GetInstance()使用懒惰初始化,也就是说它的返回值是当这个函数首次被访问时被创建的。这是一种防弹设计——所有GetInstance()之后的调用都返回相同实例的指针:

#include <iostream>
using namespace std;

class Singleton
{
public:
    static Singleton *GetInstance()
    {
        if (m_Instance == NULL )
        {
            m_Instance = new Singleton ();
        }
        return m_Instance;
    }

    static void DestoryInstance()
    {
        if (m_Instance != NULL )
        {
            delete m_Instance;
            m_Instance = NULL ;
        }
    }
     // This is just a operation example
    int GetTest()
    {
        return m_Test;
    }

private:
    Singleton(){ m_Test = 10; }
    static Singleton *m_Instance;
    int m_Test;
};

Singleton *Singleton ::m_Instance = NULL;

int main(int argc , char *argv [])
{
    Singleton *singletonObj = Singleton ::GetInstance();
    cout<<singletonObj->GetTest()<<endl;

    Singleton ::DestoryInstance();
    return 0;
}

这样就可以了,保证只取得了一个实例。但是在多线程的环境下却不行了,因为很可能两个线程同时运行到if (instance == NULL)这一句,导致可能会产生两个实例。于是就要在代码中加锁。

Singleton* getInstance()
{
    lock();
    if (instance == NULL)
    {
       instance = new Singleton();
    }
    unlock();

    return instance;
}

但这样写的话,会稍稍影响性能,因为每次判断是否为空都需要被锁定,如果有很多线程的话,就可能会造成大量线程的阻塞。于是大神们又想出了双重锁定。

Singleton* getInstance()
{
    if (instance == NULL)
    {
        lock();
        if (instance == NULL)
        {
                instance = new Singleton();
        }
        unlock();
    }

    return instance;
}

这样只够极低的几率下,通过越过了if (instance == NULL)的线程才会有进入锁定临界区的可能性,这种几率还是比较低的,不会阻塞太多的线程,但为了防止一个线程进入临界区创建实例,另外的线程也进去临界区创建实例,又加上了一道防御if (instance == NULL),这样就确保不会重复创建了。

实现方法二:
改进资源回收的问题,实例自动销毁

#include <iostream>
using namespace std;


class Singleton
{
public:
    static Singleton* GetInstance()
    {
        if(m_Instance == NULL)  //判断是否第一次调用
            m_Instance = new Singleton();
        return m_Instance;
    }


private:
    Singleton(){ }
    static Singleton *m_Instance;


    // This is important
    class GC
    {
    public:
        ~GC()
        {
            if (m_Instance != NULL)
            {
                cout << "Here is the test" << endl;
                delete m_Instance;
                m_Instance = NULL;
            }
        }
    };
    static GC gc;
};


Singleton *Singleton::m_Instance = new Singleton();
Singleton::GC Singleton::gc;


int main(int argc, char *argv[])
{
    Singleton *singletonObj = Singleton::GetInstance();


    return 0;
}

由于程序在结束的时候,系统会自动析构所有的全局变量,实际上,系统也会析构所有类的静态成员变量,就像这些静态变量是全局变量一样。我们知道,静态变量和全局变量在内存中,都是存储在静态存储区的,所以在析构时,是同等对待的。 在程序运行结束时,系统会调用Singleton的静态成员GC的析构函数,该析构函数会进行资源的释放,而这种资源的释放方式是在程序员“不知道”的情况下进行的,而程序员不用特别的去关心,使用单例模式的代码时,不必关心资源的释放。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值