Singleton

The basic singleton

//  Singleton.h
class Singleton
{
public:
    static Singleton* Instance(){
        if(!pInstance_)
            pInstance_ = new Singleton;
        return pInstance_;
    }
private:
    Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
    ~Singleton();
    static Singleton* pInstance_;
};
//  Singleton.cpp
Singleton* Singleton::pInstance_ = 0;

The code above is the standard of Singleton we learned in school. However, such pattern is not safe in multithread programming. To address this problem, it is best to use synchronized:

class Singleton
{
public:
    static synchronized Singleton* Instance(){
        if(!pInstance_)
            pInstance_ = new Singleton;
        return pInstance_;
    }
};

Dead reference problem and its solutions

//  Singleton.h
class Singleton
{
public:
    static Singleton* Instance(){
        if(!pInstance_){
            if(destroyed_)
                OnDeadReference();
            else
                Create();
        }
        return pInstance_;
}
private:
    static void Create(){
        static Singleton theInstance;//Meyer's Singleton
        pInstance_ = &theInstance;
    }
    static void OnDeadReference(){
        throw std::runtime_error("Dead Reference Detected");
    }
    virtual ~Singleton(){
        pInstance_ = 0;
        destroyed_ = true;
    }
    static Singleton* pInstance_;
    static bool destroyed_;
};
//  Singleton.cpp
Singleton* Singleton::pInstance_ = 0;
bool Singleton::destroyed_ = false;

  Although we successfully solved the undefined behavior problems, we still have to face the unsatisfactory problem. In this case, we would utilize the phoenix singleton pattern.

//  Singleton.h
class Singleton
{
public:
    static Singleton* Instance(){
        if(!pInstance_){
            if(destroyed_)
                OnDeadReference();
            else
                Create();
        }
        return pInstance_;
}
private:
    static void KillPhoenixSingleton();
    static void Create(){
        static Singleton theInstance;//Meyer's Singleton
        pInstance_ = &theInstance;
    }
    virtual ~Singleton(){
        pInstance_ = 0;
        destroyed_ = true;
    }
    static Singleton* pInstance_;
    static bool destroyed_;
};

void Singleton::OnDeadReference(){
    Create();
    new(pInstance_) Singleton;
    atexit(KillPhoenixSingleton);
    destroyed = false;
}

void Singleton::KillPhoenixSingleton(){
    pInstance_->~Singleton();
}
//  Singleton.cpp
Singleton* Singleton::pInstance_ = 0;
bool Singleton::destroyed_ = false;

In this case, the new operator does not allocate memory, it is called the placement new operator, which constructs objects at the address passed. Nevertheless, phoenix singleton pattern is not omnipotent, there is a solution that uses longevity to handle dead reference problem, which will not be discussed in this article

Singleton in multithreaded world

  Singleton object is a shared global resource and all global resources are always suspect for race conditions and threading issues. In this case, we would use the double-checked locking pattern to solve this problem.

Singelton& Singleton::Instance(){
    Lock guard(mutex_);
    if(!pInstance_)
        pInstance_ = new Singleton;
    return *pInstance_;
}

  However, this solution is inconvenient and lack of efficiency, because each call to Instance incurs locking and unlocking the synchronization object. The perfect solution is as follows:

Singelton& Singleton::Instance(){
    if(!pInstance_){
        Lock guard(mutex_);
        if(!pInstance_)
            pInstance_ = new Singleton;
    }   
    return *pInstance_; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值