有人告诉我,我的单件模板可能不是真正的单身人士,因为有办法用它创建多个对象。当我问如何解决它时,我被忽略了。这就是为什么我来这里问我的单身模板类真的是单身?
#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 >
{
};
答案 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类不太可能导致多个实例。