c++ --单例的实现

        单例的实现有很多的坑,并不是简单的一个static的成员获取就算是单例了,下面详细叙述下它的坑。

        -.  懒汉模式

        

class singleton
{
	private;
		singleton();
	public:
		~singleton();
	    static singleton getInstance();
		{
				static singleton minstance;
				return minstance;
		}
};

      懒汉模式在一般使用下都不会有问题,但是,这个实现是线程不安全的。局部静态变量static singleton minstance ,编译器会在编译时期对其做处理,其结果如下:

    

static bool s_constructed = false;
  static uninitialized singleton minstance;
  if (!s_constructed) {
      s_constructed = true;
      new(&minstance) minstance; // construct it
  }

 从这里可以显而易见到存在线程安全的问题。那对于这种情况怎么处理呢? 最简单的就是实用恶汉模式。

     二. 饿汉模式

我们知道 , 全局成员,类静态成员,都是在main函数执行前进行初始化的,而局部静态成员是在运行到它的时候才进行初始化,所以饿汉模式就是在程序还没有运行的时候,就对单例进行初始化。

    

class singleton
{
	private;
		singleton();
		static singleton minstance;
	public:
		~singleton();
	    static singleton getInstance();
		{
				return minstance;
		}
};
singleton singleton::minstance;
这样,就不会存在编译器对于懒汉模式所做的处理了,在main函数执行前,singleton对象就已经够造了出来,这样就是一个线程安全的单例模式了。

     以为这就是单例模式最终的形态了吗? too young too simple!!!!!

     参考了boost的单例模式实现:

     

template <typename T>
struct Singleton
{
    struct object_creator
    {
        object_creator(){ Singleton<T>::instance(); }
        inline void do_nothing()const {}
    };
 
    static object_creator create_object;
 
public:
    typedef T object_type;
    static object_type& instance()
    {
        static object_type obj;
        //据说这个do_nothing是确保create_object构造函数被调用
        //这跟模板的编译有关
        create_object.do_nothing();
        return obj;
    }
 
};
template <typename T> typename Singleton<T>::object_creator Singleton<T>::create_object;
    发现有这么一个实现,将单例对象还是做程局部静态变量,但是通过另一个内部类object_creator代替其在全局区声明初始化,这是什么原因呢?

    参考了一位大牛的blog,发现还有这么一种2b的用法:

    

//.h
class QMManager
{
protected:
    static QMManager instance_;
    QMManager();
    ~QMManager(){};
public:
    static QMManager *instance()
    {
        return &instance_;
    }
};
 
class QMSqlite
{
protected:
    static QMSqlite instance_;
    QMSqlite();
    ~QMSqlite(){};
public:
    static QMSqlite *instance()
    {
        return &instance_;
    }
    void do_something();
};
 
QMManager QMManager::instance_;
QMSqlite QMSqlite::instance_;

//.cpp
QMManager::QMManager()
{
    printf("QMManager constructor\n");
    QMSqlite::instance()->do_something();
}
 
QMSqlite::QMSqlite()
{
    printf("QMSqlite constructor\n");
}
void QMSqlite::do_something()
{
    printf("QMSqlite do_something\n");
}

就是在构造类静态成员的时候,它的构造函数有可能去调用另一个单例模式的静态成员,以便调用其方法。可以发现,这是存在问题的,在执行main函数之前,两个静态成员QManager和QMsSqlite的构造是有先后顺序的,QManager先进行的初始化,这时候,当调用QManager的构造函数的时候,去主动获取QMSqlite的单例,并调用其成员,但是,这时候QMSqlite的单例对象instance_还没有初始化,就是说,现在调用的是一个为初始化的变量,这当然存在问题了。 解决的办法就是,将这两个变量的初始化工作放在局部变量,让程序运行到的时候去初始化。但是这样就又会出现懒汉模式中的线程不安全的问题,所以,讨巧的做法就是把他们封装进另一个静态成员的构造中。

    最终的单例模式:


   

class singleton
{
	private:
		singleton();
	    class create_object
		{
			public:
				create_object(){
						singleton::getInstance();
				}
		};
		static create_object m_createobj;	
	public:
		~singleton();
	    static singleton& getInstance();
		void eat()
		{
			printf("fuck\n");
		}	

};
singleton::create_object singleton::m_createobj; 

singleton::singleton()
{

}

singleton::~singleton()
{

}

singleton& singleton::getInstance()
{
	static singleton m_instance;
	return m_instance;
}

    小小的单例模式,有这么多的坑

   贴一段模仿boost的实现:

    

#include "stdafx.h"
#include <iostream>


using namespace std;

class signletonSt
{
private:
	signletonSt(){}
	~signletonSt(){}
	struct create_signletonst
	{
		create_signletonst()
		{
			signletonSt::getInstance();
		}
	};
	static create_signletonst m_creator;
	
public:
	static signletonSt* getInstance()
	{
		static signletonSt* m_st = NULL;
		if (!m_st)
		{
			cout << "first new" << endl;
			m_st = new signletonSt();
		}
		else
		{
			cout << "has instanced" << endl;
			return m_st;
		}
	}
	
};

signletonSt::create_signletonst signletonSt::m_creator;

int _tmain(int argc, _TCHAR* argv[])
{
	signletonSt* m1 = signletonSt::getInstance();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值