[转] boost库的Singleton的实现以及static成员的初始化问题

http://www.cnblogs.com/kex1n/archive/2011/04/05/2006194.html

effectie c++的条款4中提到:

(global对象,定义在namespace内的对象,class内的static对象,函数内的static对象,file作用域内的 static对象)统称为static对象。其中函数内的static对象又叫local static object, 其他的叫non-local static object。

non-local static object的初始化顺序是没有定义的,local static object在函数第一次调用时构造初始化。

还有:non-local static object会在main函数之前被初始化。

#pragma once
#include <iostream>
using namespace std;

class Foo
{
public:
    Foo()
    {
        cout<<"Foo create!"<<endl;
    }
};

class Test
{
public:
    Test() {}
    Foo GetX() const{ return x_;}
private:
    static Foo x_;
};

Foo Test::x_;

即使在main函数中未初始化Test对象,仍会看到Foo Create的提示,所以non-local static object在main函数之前初始化的。

普通的singleton模式:

#pragma once
template<typename T>
class Singleton_
{
public:
    static T&Instance()
    {

   static T t_;
        return t_;
    }
private:
    Singleton_() {}
};

多线程的时候此方法不给力,可以用加锁的办法,参见ACE实现的双重加锁优化的singleton实现。或要求使用者在main的早期或多线程环境之前把所有单件各调用一次instance()

由于non-local static object是在main之前初始化的,默认进入main函数之前只有主线程运行,则有如下写法

#pragma once

template<typename T>
class Singleton_
{
public:
    static T&Instance()
    {
        return t_;
    }

private:
    Singleton_() {}

    static T t_;
};

template <typename T> T Singleton_<T>::t_;

这样实现的问题是,无法预知对象的生成的顺序,如果多个单件对象有初始化次序要求会出现问题,比如一个单件构造函数中会调用另一个单件的instance(),而那个单件还没有构造。
Boost的实现可以解决这两个问题。

下面看boost的singleton实现:

class Widget
{
public:
    Widget()
    {
        cout<<"Widget Creat"<<endl;
    }
};


template <typename T>
struct Singleton
{

private:
    struct object_creator
    {
        object_creator()
        {
            Singleton<T>::instance();
        }

        inline void do_nothing()const
        {}
    };

    static object_creator create_object;

    Singleton () {}

public:
    typedef T object_type;
    static object_type& instance()
    {
        static object_type obj;
        create_object.do_nothing();
        return obj;
    }
};


//声明一个全局变量template <typename T> Singleton<T>::create_object
typename Singleton<T>::object_creator       Singleton<T>::create_object;

int main()
{
    Widget& w = Singleton<Widget>::instance();

    return 0;
}

没有使用锁机制,而是充分利用了C++的语言特性较好的解决了多线程情况下使用singleton的问题。
boost的singleton的实现基于以下假设:良好的设计在进入main函数之前应该是单线程的。
我们可以使用全局变量的方式来设计singleton,并且保证在使用该singleton之前其已经被正确的初始化。

在进入main之前,唯一的主线程开始构造Singleton<T>::create_object,在其构造函数之内调用 Singleton的instance函数,并在该函数内生成Singleton对象,至于函数donoting(),去掉之后照样可以通过编译,我想原 因可能是为了再次保证singleton的初始化完全成功。

posted @ 2015-03-09 16:26  枪侠  阅读(529)  评论(0编辑  收藏  举报