这是Singleton模式的正确实现吗?

时间:2012-11-15 13:21:05

标签: c++ templates singleton

以下代码是我对Singleton Pattern的实现。

 #include <iostream>

template<class T>
class Uncopyable
{
protected:
    Uncopyable(){}
    ~Uncopyable(){}
private:
    Uncopyable(const Uncopyable<T>&);
    Uncopyable& operator=(const Uncopyable<T>&);
};

template <class T>
class Singleton : private Uncopyable<T>
{
public:
    static T* getInstancePtr()
    {
        return instance;
    }
protected:
    Singleton<T>()
    {
        if(instance == 0)
        {
            instance = new T();
        }
    };
    ~Singleton<T>()
    {

    };
private:
    static T* instance;
};
template<class T> T* Singleton<T>::instance = 0;

class Test : public Singleton<Test>
{
public:
    Test(){};
    ~Test(){};
    inline void test() const
    {
        std::cout << "Blah" << std::endl;
    }
private:
    friend class Singleton<Test>;
protected:
};

int main(int argc, char* argv[])
{
    Test* t = Test::getInstancePtr();
    Test* t2 = Test::getInstancePtr();

    t->test();
    t2->test();

    return 0;
}

它以这种形式工作,但我不确定它是否真的是正确的,因为Singleton的构造函数和析构函数受到保护而不是私有。如果我将它们声明为私有,则代码将无法编译,因为类无法访问它们。这个实现是否可以安全使用,或者我可以做些什么来改进它以确保只创建和使用一个实例。

由于

6 个答案:

答案 0 :(得分:7)

这肯定是单身人士的错误实施。该实现存在太多问题。

在C ++ 11中,您可以使用std::call_oncestd::once_flag来实现单例模式。这是一个例子:

//CRTP base singleton class

template<typename TDerived>
class Singleton 
{
    static std::unique_ptr<TDerived> m_instance;
    static std::once_flag            m_once;

protected:     

    Singleton() {}

public:

    ~Singleton() { }

    static TDerived & GetInstance() 
    {
        std::call_once
        ( 
           Singleton::m_once, 
           [] (){ Singleton::m_instance.reset( new TDerived() ); }
        );
        return *m_instance;
    }
};

template<typename TDerived> 
std::unique_ptr<TDerived>  Singleton<TDerived>::m_instance;

template<typename TDerived> 
std::once_flag   Singleton<TDerived>::m_once;

现在你可以从中得到:

class Demo : public Singleton<Demo>
{
     public:
          void HelloWorld() { std::cout << "HelloWorld" << std::endl; }
};

//call HelloWorld() function through singleton instance!
DemoSingleton::GetInstance().HelloWorld();

答案 1 :(得分:2)

您发布的代码存在一些问题。

  1. Uncopyable类不需要模板化
  2. Singleton类不是线程安全的
  3. 您的Singleton实例永远不会被删除
  4. 我会重新实现你的访问者:

    static T& GetInstance()
    {
        static T instance;
        return instance;
    }
    

    然后确保在应用程序的主线程中调用Singleton<T>::GetInstance()(在初始化期间)以避免任何线程问题。

答案 2 :(得分:1)

你的析构函数私有会导致编译错误吗?导致进程结束时,编译无法调用私有函数所以对象无法删除

答案 3 :(得分:1)

不,这不是单例模式的好实现,它不起作用! 示例中唯一的Test实例是NULL!永远不会调用构造函数!

您需要将Singleton :: getInstancePtr更改为:

public:
    static T* getInstancePtr()
    {
        if(instance == 0)
        {
            instance = new T();
        }
        return instance;
    }
protected:
   Singleton<T>() {};

现在将调用Test的构造函数。

答案 4 :(得分:0)

通常单例对象在程序的生命周期中存在,所以我没有像那样实现它们,因为你使用动态分配,然后有人必须释放它并返回指向你的单例对象的指针,然后你可能会意外删除它,所以我会用这样的东西:

template< class T >
struct Singleton : Uncopyable<T> {
public:
    static T& get_instance() {
        static T res;
        use( res ); // make sure object initialized before used
        return res;
    }
private:
    static void use( T& ) {}
};

答案 5 :(得分:0)

在C ++中没有正确实现Singleton反模式。

此尝试的主要问题是:

  • 语义非常奇怪且容易出错;您必须在某处实例化Singleton才能创建实例。您的示例永远不会创建实例,t->test()错误地通过空指针调用函数。
  • 构造不是线程安全的;如果两个未同步的线程都实例化Singleton
  • ,则可以创建两个实例
  • 如果实际创建了实例,那么它就会被泄露。

错误较少的实现可能更像是这样:

template <typename T>
T & singleton()
{
    static T instance;
    return instance;
}

但是这仍然存在问题:特别是,实例可能会在其他静态对象之前被销毁,这些静态对象可能会尝试在其析构函数中访问它。