web-dev-qa-db-ja.com

シングルトンポインターを削除する方法は?

私はシングルトンパターンを実装していました。ここでは、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;  
}     
26
Atul

もちろん、無限ループを引き起こします!

あなたはデストラクタを呼び出しますが、デストラクタはデストラクタも呼び出すので、デストラクタはデストラクタを何度も呼び出します...

deleteを使用する場合は、デストラクタのoutsideから使用する必要があり、デストラクタで再度呼び出さないでください。

そのためには、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.
       ...
   }

注:他の人はシングルトンの使用について警告しますが、このパターンはしばしば誤用されるので正しいです。それを使用する前に考えてください。とにかく先に進んでください、それは学ぶための良い方法です!

33
Offirmo

シングルトンのより適切な実装は次のとおりです。

_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

11
Paul Manta

インスタンスを削除してメインから呼び出す静的メンバーSingleton::DestroyInstance()を追加します。

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

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

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

簡単に言えば、シングルトンを使用しないでください。

長い答え、main()のシングルトンポインターでdeleteを呼び出さないでください。他のグローバル変数dtorが呼び出されているときにシングルトンを削除する何らかの静的オブジェクトを使用します。

7
wilx

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();
}

この例では、プログラムが終了している間にシングルトンが削除されます。 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>;
}
0
rich