Как удалить синглтон указатель? - PullRequest
26 голосов
/ 02 января 2012

Я реализовывал шаблон синглтона. Вот, я создаю новый экземпляр Singleton * в GetInstance, когда я пытаюсь удалить его в деструкторе, он делает это в бесконечном цикле. Как избежать утечки памяти в этом случае?

Пожалуйста, обратитесь к приведенному ниже коду:

#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 ]

33 голосов
/ 02 января 2012

Конечно, это вызывает бесконечный цикл!

Вы вызываете деструктор, но деструктор также вызывает деструктор, поэтому деструктор снова вызывает деструктор ... и снова ...

Если вы хотите использовать 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.
       ...
   }

Примечание: другие люди предупреждают вас об использовании синглтона, и они правы, потому что этот шаблон часто используется неправильно. Поэтому подумайте, прежде чем использовать его. Но все равно продолжайте, это хороший способ учиться!

20 голосов
/ 02 января 2012

Хотя в большинстве случаев рекомендуется не использовать шаблон синглтона, рекомендуется создавать статические локальные переменные в функциях для создания синглетонов:

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

Чтобы дать некоторое обоснование передовому опыту: Singleton-nage обычно не требуется, если вам не нужно представлять действительно глобальный ресурс. Синглтоны страдают от всех недостатков глобальных переменных (потому что они являются глобальными переменными с некоторой OO-заморозкой) и часто имеют мало оснований для того, чтобы быть по-настоящему единичными. Наивный программист может захотеть реализовать God как одноэлементный объект. Мудрый программист этого не делает и радуется, когда клиент оказывается многобожником.

11 голосов
/ 02 января 2012

Вот более правильная реализация синглетонов:

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

8 голосов
/ 02 января 2012

Добавьте статический член Singleton::DestroyInstance(), который удаляет экземпляр и вызывает его из основного.

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

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

int main()  
{
    Singleton* pInstance = Singleton::GetInstance();
    /* ... */
    Singleton::DestroyInstance();    
}  
7 голосов
/ 02 января 2012

Краткий ответ, не используйте синглтоны.

Более длинный ответ, никогда не вызывайте delete для одноэлементного указателя в main(). Используйте некоторый статический объект, который будет удалять синглтон при вызове других глобальных переменных dtors.

0 голосов
/ 22 ноября 2016

с использованием SingletonHolder из библиотеки Loki, написанной Андреем Александреску.

#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 будет удален во время завершения программы. Есть также некоторые другие состояния для создания одноэлементного указателя, используя malloc, static ... более подробно взгляните на: http://loki -lib.sourceforge.net / html / a00628.html

Альтернативно вы можете создать синглтон, просто используя статическую переменную:

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

class Singleton
{
   ...
private:
   friend struct CreateUsingStatic<Singleton>;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...