singleton

最近碰到一个同事讨论全局访问的对象,想起来这个模式,比起这个模式更有意思的是这个模式各种实现中学习到的c++知识。

记录下我曾经学习到的单件模式,和曾经实现的版本。我给他提供的实现是meyer版本:

template<typename Type>
class Singleton
{
public:
    static Type& GetInstance()
    {
        static Type value;
        return value;
    }
};


template<typename Type>
class Singleton;
class UserType
{
    UserType()
    {

    }
    ~UserType()
    {

    }
    friend class Singleton<UserType>;
public:
};
记得设计模式中没有考虑多线程,我提供一个类似的c++实现:

template<typename Type>
class Singleton
{
public:
    static Type& GetInstance()
    {
        if(_instance==nullptr){
            _instance=new Type;
        }
        return *_instance;
    }
private:
    static Type* _instance;
};
template<typename Type>
Type* Singleton<Type>::_instance=nullptr;
在这个基础上增加多线程锁,就是所谓的双重检测版本

#include <mutex>
template<typename Type>
class Singleton
{
public:
    static Type& GetInstance()
    {
        if(_instance==nullptr){
            std::lock_guard<std::mutex> lock(_mutex);
            if(_instance==nullptr){
                _instance=new Type;
            }
        }
        return *_instance;
    }
private:
    static Type* _instance;
    static std::mutex _mutex;
};
template<typename Type>
Type* Singleton<Type>::_instance=nullptr;

template<typename Type>
std::mutex Singleton<Type>::_mutex;
再后来,又是meyer发了篇论文说由于乱序,双重检测也不保险。就有了开始的meyer版本。不得不说的loki的实现,这个可以看书,也可以直接看源码,实现太繁琐,不贴代码了。上面的实现new出来后没有delete,loki中使用atexit函数,在程序exit中调用来释放内存。为了解决乱序的问题,使用atomic,有了如下实现,主要是memory battery解决了乱序的bug:

#include <atomic>
#include <mutex>
class spinlock_mutex
{
    std::atomic_flag flag=ATOMIC_FLAG_INIT;
public:
    void lock()
    {
        while (!flag.test_and_set(std::memory_order_acquire));
    }
    void unlock()
    {
        flag.clear(std::memory_order_release);
    }
};

template<typename Type>
class Singleton
{
public:
    static Type& GetInstance()
    {
        if(_instance==nullptr){
            std::lock_guard<spinlock_mutex> lock(_mutex);
            if(_instance==nullptr){
                _instance=new Type;
            }
        }
        return *_instance;
    }
private:
    static Type* _instance;
    static spinlock_mutex _mutex;
};
template<typename Type>
Type* Singleton<Type>::_instance=nullptr;

template<typename Type>
spinlock_mutex Singleton<Type>::_mutex;
在上面的基础上,我给singleton增加ReleaseInstance函数,用来在程序退出时,手动释放对象,控制释放顺序,辅助类helper的存在是为了没有主动调用ReleaseInstance时,自动释放对象。

#include <atomic>
#include <mutex>
class spinlock_mutex
{
    std::atomic_flag flag=ATOMIC_FLAG_INIT;
public:
    void lock()
    {
        while (!flag.test_and_set(std::memory_order_acquire));
    }
    void unlock()
    {
        flag.clear(std::memory_order_release);
    }
};

template<typename Type>
class Singleton
{
    class Helper
    {
    public:
        ~Helper()
        {
            ReleaseInstan();
        }
    };
public:
    static Type& GetInstance()
    {
        static Helper helper;
        if(_instance==nullptr){
            std::lock_guard<spinlock_mutex> lock(_mutex);
            if(_instance==nullptr){
                _instance=new Type;
            }
        }
        return *_instance;
    }
    static void ReleaseInstan()
    {
        if(_instance){
            delete _instance;
            _instance=nullptr;
        }
    }
private:
    static Type* _instance;
    static spinlock_mutex _mutex;
};
template<typename Type>
Type* Singleton<Type>::_instance=nullptr;

template<typename Type>
spinlock_mutex Singleton<Type>::_mutex;

还有使用call_once

#include <mutex>
template<typename Type>
class Singleton
{
    class Deleter
    {
    public:
        ~Deleter()
        {
            if(_instance){
                delete _instance;
                _instance=nullptr;
            }
        }
    };
public:
    static Type& GetInstance()
    {
        static Deleter deleter;
        std::call_once(_flag,[](){
            _instance=new Type;
        });
        return *_instance;
    }

private:
    static Type* _instance;
    static std::once_flag _flag;
};
template<typename Type>
Type* Singleton<Type>::_instance=nullptr;

template<typename Type>
std::once_flag Singleton<Type>::_flag;

单件模式不喜欢,本身代码也比较简单,但是各种不同的单件实现中有不同的折中,有一些好玩的东西在里面。








  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值