您的位置:首页 > 编程语言 > C语言/C++

c++ --单例的实现

2016-01-03 11:06 375 查看
        单例的实现有很多的坑,并不是简单的一个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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++