注:本文中的实现语言均为C++
Singleton
所谓的单例,指一个类只允许实例化一个对象。
一种可能的实现是:
class Singleton
{
public:
static Singleton* Instance()
{
if (!inst)
inst = new Singleton();
return inst;
}
private:
Singleton() {}
static Singleton* inst;
};
//Singleton.cpp
Singleton* Singleton::inst = 0;
构造函数不对外开放,只在类的全局函数Instance中实例化唯一的对象,这样就可以通过Singleton::Instance()来调用该对象。
Improved Singleton
有人提出以下疑问:
1)这真的是单例吗?Singleton obj = *Singleton::Instance();
如果这样写,就可以生成无数个对象。所以复制构造函数和赋值操作符重载不能对外开放,最好连实现都不要有,这样在编译期间就能发现非法的调用。
2)手动释放内存会怎么样?
delete Singleton::Instance();
这个问题很严重,所以析构函数也不能对外开放。
3)返回指针安全吗?
考虑到有可能会delete返回的值,Instance函数最好返回引用。
4)对象不释放没有问题吗?
程序结束,会释放内存,但是像文件等资源,程序是不会自己释放的,可能会资源泄漏。
5)多线程安全吗?
需要初始化时加上锁,以防多次构造。
以下是改造后的代码:
class Singleton
{
public:
static Singleton& Instance()
{
if (!pInst)
{
Lock guard(mutex_); //do not talk about thread lock here
if (!pInst)
{
Create();
}
}
return *pInst;
}
private:
Singleton() {}
Singleton(const Singleton&); //no implementation
Singleton& operator=(const Singleton&); //no implementation
~Singleton() {}
static void Create()
{
static Singleton inst;
pInst = &inst;
}
static Singleton* pInst;
};
//Singleton.cpp
Singleton* Singleton::pInst = 0;
第一次访问Create函数时,inst静态变量才会被创建。由程序结束时自动调用析构函数释放对象资源。
Phoenix Singleton(长生鸟单例)
假设一个系统中有三个单例:Display, Keyboard, Log。要求Display和Keyboard初始化和销毁时写日志,以便跟踪错误。这就要求Display和Keyboard先于Log析构。对于static变量而言,析构是在程序结束时发生的,顺序由不得我们控制,Phoenix Singleton可以解决这个问题。
长生鸟的特点是:能够从自己的灰烬中重生。
如果Log被调用的时候,发现自己已经被析构,那么就让自己再次重生吧!需要借以C标准库的atexit函数来实现重生后的灭亡。
//PhoenixSingleton.h
#include <cstdlib> //atexit
#include <new> //placement new
class PhoenixSingleton
{
public:
static PhoenixSingleton& Instance()
{
if (!pInst)
{
//Lock guard(mutex_); //do not talk about thread lock here
if (!pInst)
{
if (destroyed)
{
OnDeadReference();
}
else
{
Create();
}
}
}
return *pInst;
}
private:
PhoenixSingleton() {}
PhoenixSingleton(const PhoenixSingleton&); //no implementation
PhoenixSingleton& operator=(const PhoenixSingleton&); //no implementation
~PhoenixSingleton()
{
pInst = 0;
destroyed = true;
//release other resource
}
static void Create()
{
static PhoenixSingleton inst;
pInst = &inst;
}
static void KillPhoenixSingleton()
{
pInst->~PhoenixSingleton();
}
static void OnDeadReference()
{
Create();
new (pInst) PhoenixSingleton();
atexit(KillPhoenixSingleton);
destroyed = false;
}
private:
static PhoenixSingleton* pInst;
static bool destroyed;
};
//PhoenixSingleton.cpp
PhoenixSingleton* PhoenixSingleton::pInst = 0;
bool PhoenixSingleton::destroyed = false;
写一个测试程序(完整代码请见本文最下面的注1):Singleton是个普通的单例,它在析构的时候,调用了PhoenixSingleton:
Singleton::~Singleton()
{
mjn::log("Singleton::~Singleton()");
PhoenixSingleton::Instance();
}
main函数很简单:
int main() {
Singleton::Instance();
PhoenixSingleton::Instance();
return 0;
}
输出结果:
Reference:
《C++设计新思维》,第6章,Singletons实作技术
注:
1)PhoenixSingleton的完整测试代码,请见mjnForCsdn@126.com邮箱(密码:abc123456,文件中心->Design Pattern->Singleton->PhoenixSingleton.tar)