我正在实现一个单例模式.在这里,我在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;  
}     
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.
       ...
   }
注意:其他人警告你使用单例并且它们是正确的,因为这种模式经常被滥用.所以在使用之前要先思考 但无论如何,继续前进,这是学习的好方法!
thi*_*ton 20
虽然最佳做法是在大多数情况下不使用单例模式,但最好在函数中使用静态局部变量来创建单例:
static Singleton& Singleton::GetInstance() {
     static Singleton the_singleton;
     return the_singleton; 
}
为最佳实践提供一些理由:除非您必须代表真正的全球资源,否则通常不需要单独使用.单身人士遭受全局变量的所有缺点(因为他们是具有一些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
};
静态实例在您第一次调用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();    
}  
简短的回答,不要使用单身人士.
更长的答案,永远不要在单例指针上调用删除main().使用某种静态对象,在调用其他全局变量dtors时删除单例.