Подтвердить что ты не робот

Как удалить указатель Singleton?

Я реализовал одноэлементный шаблон. Вот, я создаю новый экземпляр 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;  
}     
4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 4

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

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

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

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

Ответ 5

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

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

Ответ 6

используя SingletonHolder of Loki-Library, написанную Андреем Александреску.

#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

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

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

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