如何删除Singleton指针?

Atu*_*tul 26 c++ singleton

我正在实现一个单例模式.在这里,我在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)

注意:其他人警告你使用单例并且它们是正确的,因为这种模式经常被滥用.所以在使用之前要先思考 但无论如何,继续前进,这是学习的好方法!

  • "所以在使用它之前先想想.但无论如何,继续前进,这是学习的好方法!" 这是一个很好的建议,找出人们为什么反对意见的最佳方法是做到这一点,并得出相同的结论. (9认同)

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


Ale*_*ato 8

添加一个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)


wil*_*ilx 7

简短的回答,不要使用单身人士.

更长的答案,永远不要在单例指针上调用删除main().使用某种静态对象,在调用其他全局变量dtors时删除单例.

  • @MuhamedCicak FYI模式不是发明的.通过观察现有的代码库来发现它们.20年前做出的决定在今天证明是一个错误并不罕见,而推广单身模式的GoF书籍是从1994年开始的.FTR该书的作者之一现在说单身模式是一个错误. (2认同)