c++ --单例的实现
2016-01-03 11:06
375 查看
单例的实现有很多的坑,并不是简单的一个static的成员获取就算是单例了,下面详细叙述下它的坑。
-. 懒汉模式
懒汉模式在一般使用下都不会有问题,但是,这个实现是线程不安全的。局部静态变量static singleton minstance ,编译器会在编译时期对其做处理,其结果如下:
从这里可以显而易见到存在线程安全的问题。那对于这种情况怎么处理呢? 最简单的就是实用恶汉模式。
二. 饿汉模式
我们知道 , 全局成员,类静态成员,都是在main函数执行前进行初始化的,而局部静态成员是在运行到它的时候才进行初始化,所以饿汉模式就是在程序还没有运行的时候,就对单例进行初始化。
以为这就是单例模式最终的形态了吗? too young too simple!!!!!
参考了boost的单例模式实现:
参考了一位大牛的blog,发现还有这么一种2b的用法:
就是在构造类静态成员的时候,它的构造函数有可能去调用另一个单例模式的静态成员,以便调用其方法。可以发现,这是存在问题的,在执行main函数之前,两个静态成员QManager和QMsSqlite的构造是有先后顺序的,QManager先进行的初始化,这时候,当调用QManager的构造函数的时候,去主动获取QMSqlite的单例,并调用其成员,但是,这时候QMSqlite的单例对象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;
}
-. 懒汉模式
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++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性