单身人士被建造两次

时间:2014-02-14 17:16:02

标签: c++ static singleton

我有以下代码:

#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
#include <memory>

class Logger : public std::ofstream
{
public:
    explicit Logger(std::string const& filename = "log.txt"):
        std::ofstream(filename.c_str())
    {
        assert(*this);

        *this << "-- log file start --\n" << std::endl;
    }

    Logger::~Logger()
    {
        *this << "\n-- log file end --" << std::endl;

        this->close();
        this->clear();
    }
};

Logger logger;

template<class T>
class NotCopyable
{
public:

    NotCopyable() { }
    ~NotCopyable() { }

private:

    NotCopyable(NotCopyable const&);
    NotCopyable const& operator=(NotCopyable const&);
};

template<class T>
class Singleton : public NotCopyable<Singleton<T> >
{
public:

    static T& GetInstance()
    {
        if (!instance)
        {
            logger << "Initialize Singleton" << std::endl;

            instance.reset(new T());
        }

        return *instance;
    }

protected:

    Singleton() { }
    virtual ~Singleton() { }

private:

    static std::unique_ptr<T> instance;
};

template<class T>
std::unique_ptr<T> Singleton<T>::instance;

class Factory : public Singleton<Factory>
{
public:

    Factory() { logger << "Factory constructor" << std::endl; }
    ~Factory() { logger << "Factory destructor" << std::endl; }

    void Blargl() { logger << "Blargl" << std::endl; }

};

bool DoStuff()
{
    Factory::GetInstance().Blargl();

    return true;
}

bool Thingy = DoStuff();

int main(int, char*[])
{
    logger << "Start main()" << std::endl;

    Factory::GetInstance().Blargl();

    logger << "End main()" << std::endl;
}

这输出以下内容:

-- log file start --

Initialize Singleton
Factory constructor
Blargl
Start main()
Initialize Singleton
Factory constructor
Blargl
End main()
Factory destructor

-- log file end --

我觉得很愚蠢,但看不出为什么工厂被建造两次而不是一次。这是怎么回事?

1 个答案:

答案 0 :(得分:4)

我尝试运行您的代码,并且具有您在OSX,Apple llvm 5.0上描述的相同行为 如果在GetInstance()方法中定义静态实例变量,它可以正常工作:

static T& GetInstance()
{
    static std::unique_ptr<T> instance
    if (!instance)
    {
        logger << "Initialize Singleton" << std::endl;

        instance.reset(new T());
    }

    return *instance;
}

我认为您的代码中存在的问题是Singleton :: instance在其声明点(默认构造函数)的初始化与GetInstance()方法中的赋值之间的未指定执行顺序。
所以,如果我说的是对的,那么执行的顺序可能就像:

  1. GetInstance()来自DoStuff()来电
  2. Singleton<Factory>::instance
  3. 的默认构造
  4. GetInstance()
  5. 内的新main()来电

    编辑:使用以下代码测试我的理论:

    template <typename T>
    class Ptr {
    public:
        Ptr()
        : p() {
            std::cout << "Initalizing Ptr" << std::endl;
        }
    
        std::unique_ptr<T> p;
    };
    
    
    
    template<class T>
    class Singleton : public NotCopyable<Singleton<T>> {
    public:
        static T& GetInstance()
        {
            if (!instance.p)
            {
                std::cout << "Initalizing Singleton" << std::endl;
                logger << "Initialize Singleton" << std::endl;
                instance.p.reset(new T());
            }
        return *instance.p;
    }
    
    protected:
        Singleton() { }
        virtual ~Singleton() { }
    
    private:
        static Ptr<T> instance;
    };
    
    template<class T>
    Ptr<T> Singleton<T>::instance;
    

    输出:

    1. Initalizing Singleton
    2. Initalizing Ptr
    3. Initalizing Singleton