【3】设计模式之单例模式(Singleton)

本文详细介绍了单例模式的实现方式及其在多线程环境下的应用。通过五个不同的代码示例,展示了如何解决线程安全问题,并逐步优化性能。

1、单例模式简介

单例模式通过维护一个static的成员变量来记录这个唯一的对象实例,通过提供一个static的接口instance来获取唯一的实例。关系图

2、示例

本文使用的实例均摘自网络,在此处只是整理工作

1)单例模式代码示例(一):最简单的单例模式

//Singleton1.h
#ifndef __Singleton__Singleton1__
#define __Singleton__Singleton1__

#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;
        }
    }
    int getTest()
    {
        return m_Test;
    }
private:
    Singleton() {m_Test = 10;}
    static Singleton* m_Instance;
    int m_Test;
};

#endif /* defined(__Singleton__Singleton1__) */
//main.cpp
#include "Singleton1.h"
#include <iostream>
Singleton* Singleton::m_Instance = NULL;

int main(int argc, const char * argv[]) {
    // insert code here...
    Singleton* single = Singleton::getInstance();
    cout << single->getTest() << endl;
    return 0;
}
打印结果


这是最简单也是最普遍的实现方式,但是这种方式没有考虑到多线程的问题,在多线程的情况下,可能创建多个Singleton实例。

2)单例模式代码示例(二):示例(一)改善的代码

#ifndef __Singleton__Singleton2__
#define __Singleton__Singleton2__

#include <iostream>
using namespace std;
class Singleton
{
public:
    static Singleton* getInstance()
    {
        if(m_Instance == NULL)
        {
//            Lock();//C++没有直接的Lock操作,可以使用其他库的Lock,比如Boost,此处仅说明
            if(m_Instance == NULL)
            {
                m_Instance = new Singleton();
            }
//            UnLock();//C++没有直接的Lock操作,可以使用其他库的Lock,比如Boost,此处仅说明
        }
        return m_Instance;
    };
    static void DestoryInstance()
    {
        if (m_Instance != NULL)
        {
            delete m_Instance;
            m_Instance = NULL;
        }
    }
    int getTest()
    {
        return m_Test;
    }
    
private:
    Singleton(){m_Test = 0;}
    static Singleton* m_Instance;
    int m_Test;
};

#endif /* defined(__Singleton__Singleton2__) */
此处进行了两次m_Instance == NULL的判断,是借鉴了Java的单例模式实现时,使用的所谓“双检锁”机制,因为进行一次加锁和解锁需要付出对应的代价,而进行两次判断,就可以避免多次加锁与解锁操作,同时也保证了线程安全,但是如果在大数据操作的项目中,加锁操作将成为一个性能的瓶颈,下面就出现了第三种单例代码。

3)单例模式代码示例(三)

//Singleton.h
#ifndef __Singleton__Singleton3__
#define __Singleton__Singleton3__

#include <iostream>
using namespace std;
class Singleton
{
public:
    static Singleton* getInstance()
    {
        return const_cast<Singleton*>(m_Instance);
    }
    static void DestoryInstance()
    {
        if(m_Instance != NULL)
        {
            delete m_Instance;
            m_Instance = NULL;
        }
    }
    int getTest()
    {
        return m_Test;
    }
private:
    Singleton() {m_Test = 10;}
    <span style="color:#cc0000;">static const Singleton* m_Instance;
</span>    int m_Test;
};

#endif /* defined(__Singleton__Singleton3__) */


//main.cpp
#include "Singleton3.h"
#include <iostream>
<span style="color:#cc0000;">const Singleton* Singleton::m_Instance = new Singleton();
</span>
int main(int argc, const char * argv[]) {
    // insert code here...
    Singleton* single = Singleton::getInstance();
    cout << single->getTest() << endl;
    return 0;
}
因为静态初始化在程序开始时,也就是进入主函数之前,由于主线程以单线程方式完成初始化,所以静态初始化实例保证了线程安全性,在性能要求较高时,就可以使用这种方式,从而避免频繁的加锁解锁造成的资源浪费,但是该方法没有实现实例的销毁。下面出现了示例(四)

4)单例模式代码示例(四)

//Singleton4.h
#ifndef __Singleton__Singleton4__
#define __Singleton__Singleton4__

#include <iostream>
using namespace std;
class Singleton
{
public:
    static Singleton* getInstance()
    {
        static Singleton m_Instance;
        return &m_Instance;
    }
    int getTest()
    {
        return m_Test;
    }
private:
    Singleton() {m_Test = 10;}
    int m_Test;
};

#endif /* defined(__Singleton__Singleton4__) */

//main.cpp
#include "Singleton4.h"
#include <iostream>

int main(int argc, const char * argv[]) {
    // insert code here...
    Singleton* single = Singleton::getInstance();
    cout << single->getTest() << endl;
    return 0;
}

5)单例模式代码示例(五)

//Singleton.h
#ifndef __Singleton__Singleton__
#define __Singleton__Singleton__

#include <iostream>
using std::cout;
using std::endl;
using std::string;

class Singleton
{
public:
    static Singleton* getInstance()
    {
        if(m_Instance == NULL)
        {
            m_Instance = new Singleton();
        }
        return m_Instance;
    }
    int getTest()
    {
        return m_Test;
    }
private:
    Singleton() {m_Test = 10;}
    static Singleton* m_Instance;
    int m_Test;
    class GC
    {
    public:
        ~GC()
        {
            if(m_Instance != NULL)
            {
                cout << "Here is the test" << endl;
                delete m_Instance;
                m_Instance = NULL;
            }
        }
    };
    static GC gc;
};

#endif /* defined(__Singleton__Singleton__) */

//使用在main.cpp中
//main.cpp
#include "Singleton.h"
#include <iostream>
Singleton* Singleton::m_Instance = NULL;
Singleton::GC Singleton::gc;

int main(int argc, const char * argv[]) {
    // insert code here...
    Singleton* single = Singleton::getInstance();
    cout << single->getTest() << endl;
    return 0;
}
打印结果

在程序运行结束时,系统会调用Singleton的静态成员GC的析构函数,该析构函数会进行资源的释放,而这种资源的释放方式是在我们不知情的情况下进行的。原因是:由于程序在结束的时候,系统会自动析构所有的全局变量,实际上系统也会析构所有类的静态成员变量,静态变量和全局变量一样,存储在静态存储区,所以析构时是同等对待的。此方法是借助一个内部GC类,来释放资源。要熟练使用这种技巧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值