单例模式(Singleton)

注:本文中的实现语言均为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)

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页