各单件模式写法解析

82 篇文章 0 订阅

方式一、

class Singleton
{
public:
    static Singleton & instance()
    {
        return(s_instance);
    }

private:
    ~Singleton()
    {

    }

    static Singleton s_instance;
};

Singleton Singleton::s_instance; 
点评:“如果有SingletionA和SingletonB,在SingletonA的构造函数中使用SingletonB的实例,由于C++标准并没有明确说明静态变量的初始化顺序,所以有可能造成此时SingletonB还没有初始化的情况,而引发错误。”



方式二、
class Singleton
{
public:
    static Singleton & instance()
    {
        static Singleton s_instance;
        return(s_instance);
    }

private:
    ~Singleton()
    {

    }
};
点评:“Singleton的构造函数只会在第一次调用instance()时被初始化, 缺点是在多线程环境下会出问题。”



方式三、

class Locker;


extern Locker locker;


class Singleton
{
public:
    static volatile Singleton * instance()
    {
        if (nullptr == s_instance)
        {
            locker.acquire();
            if (nullptr == s_instance)
            {
                s_instance = new Singleton;
            }
            locker.release();
        }
        return(s_instance);
    }


private:
    ~Singleton()
    {


    }


    static volatile Singleton * s_instance;
};


volatile Singleton * Singleton::s_instance = nullptr;
点评:“如果上面代码没有volatile关键字,则编译器的优化可能会带来问题:比如locker.acquire()后面的s_instance的值不是从&s_instance处取的(假设此时已经非空),而是直接取自寄存器之前保留的值(假设寄存器的保存值还是空),就有问题了;这只是一种可能,还可能别处有问题。请参考volatile的含义、作用"


方式四、
template <typename T>
class Singleton
{
public:
    struct object_creator
    {
        object_creator()
        {
            Singleton<T>::instance();
        }

        inline void do_nothing() const { }
    };

    static object_creator create_object;

    static T & instance()
    {
        static T obj;
        create_object.do_nothing();
        return obj;
    }

    // 下面这句代码是我加的,显然它是有问题的,
    // 但是在VS编译器下,由于没有代码引导此函数实例化,
    // 所以这块代码不会被编译,也就不会发现有错误了。
    // int ABC() { my life is sucks! }
};

template <typename T> 
typename Singleton<T>::object_creator Singleton<T>::create_object;
目前boost库中Singleton就采用这种方式实现。此处的Singleton不仅要解决多线程下Singleton的问题,还要避免使用线程锁,只用C++本身的特型来实现多线程下的Singleton类;它是意图在开启多线程之前就构建出Singleton,并假设用户代码都是在main之后才会开启多线程 (所以,它通过将Singleton在main之前实例化,再依据之前的假设,意味着实现了在多线程开启前将Singleton实例化)

 
这点代码可能不太好理解,下面加上测试代码:
class A
{
public:
    A()
    {

    }
};

class B
{
public:
    B()
    {
        Singleton<A>::instance();
    }
};

int main()
{
    return(0);
}

解析:

虽然,代码中没有明确定义任何对象,但是B()中的“Singleton<A>::instance()”语句,导致“Singleton<A>::instance()”被实例化,接着Singleton<A>::instance()中的“create_object.do_nothing();”,导致了代码“static object_creator create_object;”和“do_nothing()”实例化,而代码“static object_creator create_object;”导致了“object_creator()”被实例化,这也使得对象create_object被创建 (在main前)

去除instance()中的“create_object.do_nothing();”,就不会推导出任何与struct object_creator有关的代码,也就不会有create_object产生,也就不能保证instance()中的obj在main之前就产生,从而出现方式二中的多线程问题,

这就是“create_object.do_nothing();”的作用:帮助引导create_object实例化 (“create_object.do_nothing();” 改成 “create_object;” 也是可以达到目的的)


参考文章:

http://leoxiang.com/dev/different-cpp-singleton-implementaion

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值