我的单身人士模板真的是单身吗?

时间:2012-06-29 19:19:59

标签: c++ design-patterns

有人告诉我,我的单件模板可能不是真正的单身人士,因为有办法用它创建多个对象。当我问如何解决它时,我被忽略了。这就是为什么我来这里问我的单身模板类真的是单身?

#ifndef SINGLETON_H_
#define SINGLETON_H_

template <class T>
class Singleton
{
private:
static T* instance;

protected:
    Singleton<T>(  )
    {
    }

public:
    static T* getInstancePtr(  )
    {
        if ( instance == 0 )
            instance = new T(  );

        return instance;
    }
};

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

#endif

然后由一个我希望成为单身的类继承: -

class Console : public Singleton< Console >
{
};

6 个答案:

答案 0 :(得分:4)

您已经制作了默认构造函数protected。派生类可以访问它,因此这将编译:

Console c1, c2;

答案 1 :(得分:3)

为什么你不能保证它是单身的一个简单原因是由于线程安全。

如果两个或多个线程同时调用getInstancePtr,则最终可能会有两个或更多个实例,具体取决于线程交换。

答案 2 :(得分:2)

使用本地静态变量来实现单例模式:

template <class T>
class Singleton
{
    static T* getInstancePtr(  )
    {
        static T instance; // <-- HERE

        return &instance;
    }
};

除了少得多的代码外,它还保证了线程安全。它将在第一次调用Singleton<X>::getInstancePtr()时构建,连续调用将获得一个实例。

或者,如果您希望每个线程有一个实例,则可以使用thread_local代替:

template <class T>
class Singleton
{
    static T* getInstancePtr(  )
    {
        thread_local T instance; // <-- HERE

        return &instance;
    }
};

答案 3 :(得分:1)

我使用了与您相同的单例模板,但将其留给用户创建私有构造函数和析构函数。 用户必须与单例类成为朋友,但它接近我想要的,它可以用作单例。 它不是线程安全的(但是),但它“解决了”多实例问题。

答案 4 :(得分:0)

要在多线程环境中工作,您需要一个不同的解决方案。您必须使用特定的语言功能,以确保在存在多个线程的情况下仅创建对象的一个​​实例。一种比较常见的解决方案是使用Double-Check Locking习惯用法来保持单独的线程不会同时创建单例的新实例。

答案 5 :(得分:0)

好的,除了多线程的任何问题之外,有一种情况我可以创建两个实例。通过初始化下面的类控制台

class Console : public Singleton< Console >
{
};

喜欢这样

Console c1;

我最终得到了两个Console实例,一个在Singleton类中保存的实例指针中,另一个在c1对象本身内。我通过将Singleton类更改为以下内容来解决此问题。

#ifndef SINGLETON_H_
#define SINGLETON_H_

template <class T>
class Singleton
{
private:
    static T* instance;

protected:
    Singleton<T>(  )
    {
        if ( instance == 0 )
            instance = static_cast<T*>(this);
    }

public:
    static T* getInstancePtr(  )
    {
        return instance;
    }
};

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

#endif

然而,除了多线程问题,我现在更确定我的Singleton类不太可能导致多个实例。