设计模式(三)——Singleton
Writen by Fox(yulefox.at.gmail.com)
不知道Singleton算不算用的最多的,平时用的时候,往往都是直接敲下面一段:
class CSingleton
{
public:
static void Initial(void) { if( NULL == m_pInst ) m_pInst = new CSingleton; }
static void Release(void) { delete m_pInst; m_pInst = NULL; }
static CSingleton* GetInst(void) { return m_pInst; }
private:
CSingleton() {}
~CSingleton() {}
Singleton(const Singleton&);
Singleton& operator=(const Singleton &);
static CSingleton* m_pInst;
};
不是不想改,就是懒,敲多了已经不觉得这么写多浪费时间了,按大家的说法,这样写至少有这么几个缺点:
1. 必须在程序结束前手动释放,这不仅是RP问题,如果你借了内存不主动还,说明你RP差,但被别人搞丢了(宕机)导致你还不上,说明别人RP差?所以,这还是个问题;
2. 线程同步问题,如果Singleton实例跨线程使用,上例不安全,在Initial和Release时加锁可以解决;
3. 最大的问题:不能重用。
有人给出了下面的实现:
template<class T>
class CSingleton
{
public:
static T& instance()
{
static T _instance;
return _instance;
}
private:
CSingleton() {}
~CSingleton() {}
CSingleton(const CSingleton<T>&);
CSingleton<T>& operator=(const CSingleton<T>&);
};
除了线程同步问题之外,其他都解决了。
至于线程问题,我们可以把多线程问题转化成单线程问题:在进入main函数前初始化。Boost提供了一个这样的Singleton:
template <typename T>
struct singleton_default
{
public:
typedef T object_type;
static object_type & instance()
{
static object_type obj;
create_object.do_nothing(); // 需要create_object的初始化
return obj;
}
private:
struct object_creator
{
object_creator() { singleton_default<T>::instance(); } // 创建实例
inline void do_nothing() const { }
};
static object_creator create_object;
singleton_default();
};
template <typename T>
typename singleton_default<T>::object_creator
singleton_default<T>::create_object;
由于create_object将在被调用(static object_type & instance())之前进行初始化,因此singleton_default对象的初始化被放到了main之前。
非常巧妙的一个设计。
这样一来,我们可以通过下面这样一个简单的宏完成Singleton的使用:
#define GetInst(CLASS_NAME) \
singleton_default<CLASS_NAME>::instance()
在后面需要使用到某个类的Singleton时,直接使用该宏即可。
Kevin之前提到关于静态变量的初始化顺序问题,今天查了一下ISO C++,3.6.2(Initialization of non-local objects)有段话:
// – File 1 –
#include "a.h"
#include "b.h"
B b;
A::A(){
b.Use();
}
// – File 2 –
#include "a.h"
A a;
// – File 3 –
#include "a.h"
#include "b.h"
extern A a;
extern B b;
int main() {
a.Use();
b.Use();
}
It is implementation-defined whether either a or b is initialized before main is entered or whether the initializations are delayed until a is first used in main. In particular, if a is initialized before main is entered, it is not guaranteed that b will be initialized before it is used by the initialization of a, that is, before A::A is called. If, however, a is initialized at some point after the first statement of main, b will be initialized prior to its use in A::A.
大致意思是说如果在进入main之前初始化,a和b的初始化顺序将不能确定,如果希望初始化顺序可以确定的话,就应该像上面的singleton一样在逻辑上为他们人为建立依赖。
相关链接:
Boost: http://www.boost.org
CppBlog: http://www.cppblog.com/dyj057/archive/2005/09/20/346.aspx
Wikipedia: http://en.wikipedia.org/wiki/Double-checked_locking
Double-Checked Locking: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Kevin: http://www.cppblog.com/kevinlynx/archive/2008/11/11/66623.html
昨天还在说设计模式停了很久,今天上午coding的时候,就想写一个好点的Singleton模式。每次都要这么敲,敲多了想想也烦,之所以不想写个基类,两个原因:一是因为我对继承天生没好感,二是我对模板天生没好感。似乎水平越不怎么样的coder身上臭毛病越多啊?
相关阅读
转载注明:游戏人生(http://www.yulefox.com/)
联系作者:
引用通告:http://www.yulefox.com/20081119/design-patterns-03.html/trackback/





呵呵
最好的singleton是全局空间,再脑子里做对实例的引用计数
我一般不用自动构造对象的单实例,因为先后顺序不受控制,我一般用下面的这种
/// 采用外部new和delete,这种单实体的好处是外部能控制构造和析构的顺序
template
class Singleton
{
protected:
static T* _instance;
public:
Singleton()
{
assert(!_instance);
#if defined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1200
int offset = (int)(T*)1 - (int)(Singleton*)(T*)1;
_instance = (T*)((int)this + offset);
#else
_instance = static_cast(this);
#endif
}
~Singleton()
{
assert(_instance);
_instance = 0;
}
static T& getSingleton() { assert(_instance); return (*_instance); }
static T* getSingletonPtr() { return _instance; }
};
template T* Singleton ::_instance = 0;
// 使用:
class MyClass : public Singleton
{
};
// 创建
new MyClass();
// do something
// 删除
delete MyClass::getSingletonPtr();
@PeakGao,不显示的情况了,我都不知道怎么回事……- -#&); & operator=(const CSingleton &);
大概又出现
如果希望控制初始化的地方的话,使用:
template
class CSingleton
{
public:
static T& instance()
{
static T _instance;
return _instance;
}
private:
CSingleton() {}
~CSingleton() {}
CSingleton(const CSingleton
CSingleton
};
也可以满足。