我正在实现一个单例模式.在这里,我在GetInstance中创建一个新的Singleton*实例,当我尝试在析构函数中删除它时,它在无限循环中执行.在这种情况下如何避免内存泄漏?
请参考下面的代码:
#define NULL 0
class Singleton
{
private :
static Singleton* m_pInstance;
Singleton(){};
public :
static Singleton* GetInstance()
{
if(m_pInstance == NULL)
{
m_pInstance = new Singleton();
}
return m_pInstance;
}
~Singleton()
{
//delete m_pInstance; // The system goes in infinate loop here if i uncomment this
m_pInstance = NULL;
}
};
Singleton* Singleton ::m_pInstance = NULL;
int main()
{
Singleton* pInstance = Singleton::GetInstance();
delete pInstance;
}
Run Code Online (Sandbox Code Playgroud)
Off*_*rmo 33
当然它会导致无限循环!
你调用析构函数,但析构函数也调用析构函数,因此析构函数再次调用析构函数......再次...
如果要使用delete
,必须在析构函数外部使用它,而不是在析构函数中再次调用它.
为此,您可以使用另一个静态方法来镜像该GetInstance()
方法:
class Singleton
{
public :
...
// this method is a mirror of GetInstance
static void ResetInstance()
{
delete m_pInstance; // REM : it works even if the pointer is NULL (does nothing then)
m_pInstance = NULL; // so GetInstance will still work.
}
...
~Singleton()
{
// do destructor stuff : free allocated resources if any.
...
}
Run Code Online (Sandbox Code Playgroud)
注意:其他人警告你使用单例并且它们是正确的,因为这种模式经常被滥用.所以在使用之前要先思考 但无论如何,继续前进,这是学习的好方法!
thi*_*ton 20
虽然最佳做法是在大多数情况下不使用单例模式,但最好在函数中使用静态局部变量来创建单例:
static Singleton& Singleton::GetInstance() {
static Singleton the_singleton;
return the_singleton;
}
Run Code Online (Sandbox Code Playgroud)
为最佳实践提供一些理由:除非您必须代表真正的全球资源,否则通常不需要单独使用.单身人士遭受全局变量的所有缺点(因为他们是具有一些OO结冰的全局变量),并且通常没有理由成为真正的单数.天真的程序员可能希望实现God
为单例对象.当客户变成一个多神论者时,明智的程序员不会也很高兴.
Pau*_*nta 11
这是一个更正确的单例实现:
class Singleton
{
public:
static Singleton& Instance()
{
static Singleton inst;
return inst;
}
protected:
Singleton(); // Prevent construction
Singleton(const Singleton&); // Prevent construction by copying
Singleton& operator=(const Singleton&); // Prevent assignment
~Singleton(); // Prevent unwanted destruction
};
Run Code Online (Sandbox Code Playgroud)
静态实例在您第一次调用Instance()
时创建,并在程序关闭时销毁.
但要注意使用单身人士.它们并不是邪恶的,正如一些人认为的那样(我觉得这个位置不合理),但它们很容易被滥用并且难以正确使用.根据经验,不要将单例用于"接口类"(程序其他部分使用的接口类); 尝试仅使用单例作为实现细节,并且仅在感觉合适时使用.
编辑: 一个用法示例
前段时间我在gamedev.stackexchange上发布了一个答案,我提出的解决方案使用单例作为实现的一部分,而不是接口.代码被评论并解释了为什么需要单身人士:https://gamedev.stackexchange.com/a/17759/6188
添加一个Singleton::DestroyInstance()
删除实例的静态成员,并从main调用它.
void Singleton::DestroyInstance() {
delete m_pInstance;
m_pInstance = 0;
}
/* ...................... */
int main()
{
Singleton* pInstance = Singleton::GetInstance();
/* ... */
Singleton::DestroyInstance();
}
Run Code Online (Sandbox Code Playgroud)
简短的回答,不要使用单身人士.
更长的答案,永远不要在单例指针上调用删除main()
.使用某种静态对象,在调用其他全局变量dtors时删除单例.