2010-04-01 15 views
8

Es obligatorio tener un destructor privado para una clase singleton.destructor privado para clase singleton

+1

No, no lo es. ¿Por qué preguntas? ¿Quién te obligaría? Y hacer preguntas que tienen una respuesta sí/no no es una buena idea. –

+2

Al menos estas preguntas no se pueden cerrar por ser argumentativas. ':)' – sbi

+0

@sbi: "C++ es una carga de basura vieja, estoy en lo cierto?" ;-) –

Respuesta

6

esto podría no ser lo que buscas .. Pero para referencia, lo uso de la siguiente manera:

// .h 
class Foo { 
public: 
    static Foo* getInstance(); 
    static void destroy(); 
private: 
    Foo(); 
    ~Foo(); 

    static Foo* myInstance; 
}; 

// .cpp 
Foo* Foo::myInstance = NULL; 

Foo* Foo::getInstance(){ 
    if (!myInstance){ 
     myInstance = new Foo(); 
    } 
    return myInstance; 
} 
void Foo::destroy(){ 
    delete myInstance; 
    myInstance = NULL; 
} 

Luego, al final de mi programa, yo llamo a destruir en el objeto. Como señala Péter, el sistema recuperará la memoria cuando termine su programa, por lo que no existe un motivo real. El motivo por el que uso un destructor es cuando Ogre se quejó de que no había liberado toda la memoria que asigné. Después de eso, simplemente lo uso como "buena manera", ya que me gusta limpiarlo después de mí mismo.

+1

Cuando proporciona explícitamente un 'destroy', también proporciona una abstracción con goteras. Deberías buscar Alexandrescu "Modern C++ Design" y tomar inspiración en 'Loki :: Singleton'. –

+2

Es posible que desee registrar destroy con atexit. –

+0

Lo que puedo obtener de books.google.com es que * al destruir el singleton debo eliminarlo en el cierre de la aplicación *. Pero tengo curiosidad por lo que quieres decir con abstracción con filtraciones. ¿Debo crear una nueva pregunta quizás ...? :) ¿Todavía estaría goteando si lo hago como sugiere Michael Aaron? – Default

4

Todas las clases tienen un destructor. Si no creas uno, el compilador lo hará por ti. Entonces su pregunta puede ser reformulada a: ¿El destructor para una clase singleton tiene que ser privado?

La respuesta simple es no, no tiene que ser así.

Una pregunta más interesante: ¿es una buena idea hacer que el destructor de una clase singleton sea privado?

Sí, en general, es una buena idea. Si lo haces privado, tu código de cliente no llamará al destructor por accidente. Llamar al destructor haría que el singleton fallara para todos los clientes ya que la instancia se volvería inválida.

+0

Si su singleton nunca se copia (que no debería ser, ya que eso lo haría ya no es un singleton), nunca puede quedar fuera del alcance, lo que significa que el destructor nunca se puede llamar en primer lugar (incluso accidentalmente). –

+2

@Travis: puede: 'GetSingleton() -> ~ CSingleton()' – MSalters

+0

@MSalters, pero ¿quién en su sano juicio haría eso? En mi humilde opinión, cualquier código que llame a un destructor explícitamente y que no use la ubicación nueva es muy sospechoso. –

11

Si el singleton se implementa como una variable en el ámbito global, que debe tener un público destructor . Solo los miembros públicos son accesibles a nivel mundial.

Si se declara como un miembro estático o estático local dentro de su propia clase, a continuación, el destructor puede ser privado. Se llama al destructor desde dentro del alcance de la clase, donde es accesible, cuando el programa sale. Esa es una forma de hacer que el objeto sea un singleton. ¿Necesitas hacer cumplir fuertemente eso? Si es así, sí. Depende de lo que quieras decir con "obligatorio".

class A{ 
private: 
    ~A() {} 
public: 
    static A &getGlobalA() { 
     static A a2; // <- or here - better technique 
     return a2; // this is initialized upon 1st access 
    };    // and destroyed on program exit 

    static A a; // <- constructor, destructor accessed from here 
}; 

A A::a; // <- but "called" from here in terms of control flow 
+0

El 'estático' local real es uno de la manera más conveniente. ¿Cuál es el efecto de llamar a 'getGlobalA' después de que' a2' haya sido destruido (durante la destrucción de los globales)? Me temo que llevaría a UB. –

+0

@Matthieu m: consulte este artículo para obtener una técnica simple para mitigar este problema: http://stackoverflow.com/questions/335369/finding-c-static-initialization-order-problems/335746#335746 –

1

Usted puede volver referencia a la instancia singleton.

class Factory : public IFactory 
    { 
    private: 
     /** 
     * This class should not be instantiated through its constructor. Since, it implements 
     * Singleton pattern. 
     */ 
     Factory();  
    public: 
     virtual ~Factory(); 
     /** 
     * Accessor method for singleton instance. 
     * \note use this static method to access to operations of this class. 
     */ 
     static IFactory& instance(){ 
      if(!m_instance.get()){ 
       m_instance.reset(new Factory());  
      } 
      return static_cast<IFactory&>(*m_instance); 
     } 
     /** 
     * \see IFactory::create 
     */ 
     virtual boost::shared_ptr<IConnector> create(); 
    private: 
     /* Singleton instance */ 
     static boost::scoped_ptr<Factory> m_instance; 

    }; 
+0

Aparte del hecho de que el 'static_cast' es necesario (se puede convertir implícitamente a partir de derivados de base), que no es demasiado malo. Sin embargo, hay problemas de acceso después de la destrucción que deberías intentar comprender. –

+0

No veo la necesidad de una creación dinámica. Solo crea una variable de función estática y tendrás la misma funcionalidad. Con la ventaja de que puedes controlar (hasta cierto punto) cuando se destruye para que no tengas acceso después de que se destruya. –

+0

@Martin sí, tienes razón, pero esto es solo un ejemplo de inicialización lenta. –

2

No, y en general los objetos en C++ no reciben destructores privados. Tenga en cuenta que Singleton significa que solo hay una instancia, por lo tanto, es la construcción, no la destrucción, lo que debe controlarse/evitarse. Por lo general, un producto único tiene un constructor privado, un destructor pública, una variable de instancia estática privada, y un conjunto unitario public static obtener/función de la construcción perezoso, aunque hay variaciones sobre ese patrón.

4

En mi opinión, el destructor de un signleton debe ser privada. De lo contrario, alguien puede llamar a 'eliminar' para su instancia singleton. Lo sé, normalmente nadie lo hará. Pero si hablamos de diseño de excelencia, debe ser resistente a todos los posibles daños previstos o unitnended.

Con la moderna C++ se permite declarar incluso destructores privadas para los objetos construidos de forma estática. Aquí está mi fragmento de código para Singleton:

class Singleton 
{ 
public: 
    static Singleton& GetInstance(); 

    // Before C++ 11 
private: 
    Singleton() {} 
    ~Singleton() {} 

    Singleton(const Singleton&);   // Without implementation 
    Singleton& operator=(const Singleton&); // Without implementation 

    // Since C++ 11 
private: 
    Singleton() = default; 
    ~Singleton() = default; 

public: 
    Singleton(const Singleton&)   = delete; 
    Singleton& operator=(const Singleton&) = delete; 
}; 

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