2

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

#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 >
{
};
4

6 回答 6

4

您已经创建了默认构造函数protected。派生类可以访问它,所以这将编译:

Console c1, c2;
于 2012-06-29T19:26:35.907 回答
3

不能保证它是单例的一个简单原因是线程安全。

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

于 2012-06-29T19:25:26.113 回答
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;
    }
};
于 2013-05-12T07:47:02.047 回答
1

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

于 2013-05-12T07:41:30.450 回答
0

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

于 2012-06-29T19:27:46.413 回答
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 类不太可能导致多个实例。

于 2012-06-29T20:26:50.073 回答