Singleton 实现有什么问题?
What's wrong with Singleton implementation?
请仔细阅读问题。
我在我需要单例模式的类型中使用了这个基础 class:
#pragma once
template<typename T>
class singleton
{
private:
static T* g_pInstance;
public:
static T* getInstance() { return g_pInstance; }
public:
singleton() { g_pInstance = (T*)this; }
~singleton() { if(g_pInstance == this) g_pInstance = nullptr; }
};
template<typename T>
T* singleton<T>::g_pInstance = nullptr;
用法(无 *cpp 文件):
class Any : public singleton<Any> { /* Done */ }
但是,现在我有一个奇怪的情况使用静态库中的 class,g_pInstance
指针已经设置为 0xccccccc
(未初始化为零),之前一切正常.
这是什么原因?
更新:编译器:vs 2013 x86
我同意那些抱怨您 "singleton" class 的人 - 它启用了多个实例,因此它不是标准意义上的单例。但是如果我正确理解你的问题,真正困扰你的是 Any::getInstance()
没有被 nullptr
赋值初始化,对吧?
如果是这样,那是我无法使用 g++ (GCC) 4.8.3、clang 版本 3.4.2 或 on ideone 重现的问题。我建议尝试在不同的编译器上使用您的精确代码,看看您是否可以在那里重现错误。如果不能,则可能是编译器问题:据我所知,您使用的初始化行确实是初始化静态模板数据成员的正确方法。
MSVC 在初始化模板静态方面存在一些问题。这不是您的具体情况。
我相信这可能是一个解决方案:
template<> Any* singleton<Any>::g_pInstance = nullptr;
你的单例并不是完全线程安全的,但我想你已经知道了:-)
检查这个简单的单例实现
Singleton instance declared as static variable of GetInstance method
这消除了您的实例指针初始化问题。
同意 Luu,VC 将 0xcccccccc 值分配给未初始化的指针。
单例不好,被很多人诟病,但我还是不能完全避免:-(
尝试回答为什么调用getInstance时实例指针不是nullptr。我假设应用程序中有不同的编译单元。如果发布的代码在编译单元A中,并且实例指针存在于这个A编译单元的静态范围内。我还假设存在一个编译单元 B,它有一个 class 在编译单元 B 的静态范围内声明的任何对象。由于 C++ 运行时保证仅在同一编译单元内而不是跨多个编译单元的初始化顺序。 class编译单元B中任何对象的初始化都可能发生在编译单元A中的实例指针初始化之前。这将导致在调用getInstance时在实例指针中观察到0xcccccccc。
在不将其暴露给 class 的情况下实现单例,因此您无需在源代码中对其进行初始化。并制作私有构造函数和复制构造函数。我不确定你为什么需要那些铸造的东西。你可以这样做:
#pragma once
template<typename T>
class singleton
{
private:
singleton();
singleton(const singleton&);
public:
static T& getInstance()
{
static T instance;
return instance;
}
};
请仔细阅读问题。
我在我需要单例模式的类型中使用了这个基础 class:
#pragma once
template<typename T>
class singleton
{
private:
static T* g_pInstance;
public:
static T* getInstance() { return g_pInstance; }
public:
singleton() { g_pInstance = (T*)this; }
~singleton() { if(g_pInstance == this) g_pInstance = nullptr; }
};
template<typename T>
T* singleton<T>::g_pInstance = nullptr;
用法(无 *cpp 文件):
class Any : public singleton<Any> { /* Done */ }
但是,现在我有一个奇怪的情况使用静态库中的 class,g_pInstance
指针已经设置为 0xccccccc
(未初始化为零),之前一切正常.
这是什么原因?
更新:编译器:vs 2013 x86
我同意那些抱怨您 "singleton" class 的人 - 它启用了多个实例,因此它不是标准意义上的单例。但是如果我正确理解你的问题,真正困扰你的是 Any::getInstance()
没有被 nullptr
赋值初始化,对吧?
如果是这样,那是我无法使用 g++ (GCC) 4.8.3、clang 版本 3.4.2 或 on ideone 重现的问题。我建议尝试在不同的编译器上使用您的精确代码,看看您是否可以在那里重现错误。如果不能,则可能是编译器问题:据我所知,您使用的初始化行确实是初始化静态模板数据成员的正确方法。
MSVC 在初始化模板静态方面存在一些问题。这不是您的具体情况。
我相信这可能是一个解决方案:
template<> Any* singleton<Any>::g_pInstance = nullptr;
你的单例并不是完全线程安全的,但我想你已经知道了:-)
检查这个简单的单例实现 Singleton instance declared as static variable of GetInstance method
这消除了您的实例指针初始化问题。 同意 Luu,VC 将 0xcccccccc 值分配给未初始化的指针。 单例不好,被很多人诟病,但我还是不能完全避免:-(
尝试回答为什么调用getInstance时实例指针不是nullptr。我假设应用程序中有不同的编译单元。如果发布的代码在编译单元A中,并且实例指针存在于这个A编译单元的静态范围内。我还假设存在一个编译单元 B,它有一个 class 在编译单元 B 的静态范围内声明的任何对象。由于 C++ 运行时保证仅在同一编译单元内而不是跨多个编译单元的初始化顺序。 class编译单元B中任何对象的初始化都可能发生在编译单元A中的实例指针初始化之前。这将导致在调用getInstance时在实例指针中观察到0xcccccccc。
在不将其暴露给 class 的情况下实现单例,因此您无需在源代码中对其进行初始化。并制作私有构造函数和复制构造函数。我不确定你为什么需要那些铸造的东西。你可以这样做:
#pragma once
template<typename T>
class singleton
{
private:
singleton();
singleton(const singleton&);
public:
static T& getInstance()
{
static T instance;
return instance;
}
};