【设计模式】C++单例模式的几种写法

单例模式是最简单的设计模式,就让我像玩简单的游戏一样写下去吧。

v1: 简单模式

和这个版本有过一面之缘,但不敢苟同。

class Singleton 
{
    private:
    Singleton() {}
    public:
    static Singleton * getIns()
    {
        static Singleton * ins = new Singleton();
        return ins;
    }
};

问题:何时析构不明确;最重要的是调用多次getIns函数会产生多个static Singleton指针,指向每次都调用都new出来的实例。

 

v2: 一般模式

典型写法

class Singleton 
{
    private:
    Singleton() {}
    static Singleton * ins; 
    public:
    static Singleton * getIns()
    {
        if(!ins) ins  = new Singleton();
        return ins;
    }
};

static Singleton * Singleton::ins = NULL;

问题:仍然未考虑析构问题;对象可能被复制出多个副本。

Java中由于允许在调用构造函数之前先初始化变量,因此有这样一种写法:

public class Singleton 
{
    private Singleton() {}
    public static Singleton ins = new Singleton(); 
    public static Singleton * getIns()
    {
        return ins;
    }
};

简洁明了,也是蛮OK啦,析构也省了,并且由于初始化这个语句是JVM做的,因此人工的同步也省了(不带这么欺负C++程序员的 = =)。

 

v2.1 一般模式2

 

v3: 加强模式

加入私有的复制构造函数以防出现单例对象的副本;加入一个内部静态类,整个程序结束后,静态类随着其他静态变量消亡,此时调用析构函数将ins析构。

class Singleton 
{
    private:
    Singleton() {}
    Singleton(const Singleton & s) {}
    Singleton & operator = (const Singleton & s) {}

    static Singleton * ins; 

    public:
    static Singleton * getIns()
    {
        if(!ins) ins  = new Singleton();
        return ins;
    }

    class CGarbo  // 内部类 
    {  
    public:  
        ~CGarbo()  
        {  
            if(Singleton::ins)  
                delete Singleton::ins;  
        }  
    };  
    static CGarbo Garbo; 
}; 
static Singleton * Singleton::ins = NULL;

问题:不是线程安全的。

 

v4: hard模式

    static Singleton * getIns()
    {
        pthread_mutex_init( &mutex_lock );
        if(!ins) ins  = new Singleton();
        pthread_mutex_destory( &mutex_lock );
        return ins;
    }

问题:不管ins是不是空,都要加锁,代价高

 

v5: 再接再励模式

当ins不为空时,反正getIns函数不管读写,直接返回就好了,读写锁尽可交给使用者。

    static Singleton * getIns()
    {
        if(!ins)
        {
            pthread_mutex_init( &mutex_lock );
            if(!ins) ins = new Singleton();
            pthread_mutex_destory( &mutex_lock );
        }
        return ins;
    }

自然,getIns加了锁,析构的时候也同样要加锁。继续学习,再接再励!

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。