如何删除Singleton指针?

时间:2012-01-02 09:53:41

标签: 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;  
}     

6 个答案:

答案 0 :(得分: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.
       ...
   }

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

答案 1 :(得分:20)

虽然最佳做法是在大多数情况下不使用单例模式,但最好在函数中使用静态局部变量来创建单例:

static Singleton& Singleton::GetInstance() {
     static Singleton the_singleton;
     return the_singleton; 
}

为最佳实践提供一些理由:除非您必须代表真正的全球资源,否则通常不需要单一语言。单身人士遭受全局变量的所有缺点(因为他们是具有一些OO结冰的全局变量),并且通常没有理由成为真正的单数。天真的程序员可能希望将God实现为单例对象。当顾客变成多神教徒时,明智的程序员不会也会欢喜。

答案 2 :(得分: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

答案 3 :(得分:8)

添加一个静态成员Singleton::DestroyInstance(),删除该实例并从主要文件中调用它。

void Singleton::DestroyInstance() {
    delete m_pInstance;
    m_pInstance = 0;
}

/* ...................... */

int main()  
{
    Singleton* pInstance = Singleton::GetInstance();
    /* ... */
    Singleton::DestroyInstance();    
}  

答案 4 :(得分:7)

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

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

答案 5 :(得分:0)

使用Andrei Alexandrescu编写的Loki-Library的SingletonHolder。

#include "SingletonHolder"

class Singleton
{
//not allowed ctor
private:
   Singleton()
   {}

   ~Singleton()
   {}

   ...

   //Singelton on heap
   friend struct Loki::CreateUsingNew<Singleton>;
}

Singleton& get_singleton_pointer()
{
   return Loki::SingltonHolder<Singleton>::Instance();
}

在此示例中,将在程序结束时删除Singlton。 还有一些其他的stategie使用malloc创建单例指针,静态... 更多细节看看: http://loki-lib.sourceforge.net/html/a00628.html

Alternativ你可以使用静态变量创建单例:

template <typename T>
struct CreateUsingStatic
{
   static T& get_T_singleton()
   {
      static T t;
      return t;
   }
};

class Singleton
{
   ...
private:
   friend struct CreateUsingStatic<Singleton>;
}