2010-06-22 8 views
7

Sé que hay métodos para evitar que una clase se cree en el montón evitando que el usuario use el operador new y delete. Estoy tratando de hacer todo lo contrario. Tengo una clase en la que quiero evitar que el usuario cree una instancia de la misma en la pila, y solo se compilarán las instancias iniciadas con el operador new. Más específicamente, quiero el código siguiente para recibir un error durante la compilación:C++, evitando que se cree una instancia de clase en la pila (durante la compilación)

MyClass c1; //compilation error 

MyClass* c1 = new MyClass(); //compiles okay 

De buscar en la web, me encontré con esta sugerencia sobre cómo hacerlo:

class MyClass { 
public: 
    MyClass(); 
private: 
    void destroy() const { delete this; } 

... 

private: 
    ~MyClass(); 
}; 

int main(int argc,char** argv) 
{ 
    MyClass myclass; // <--- error, private destructor called here !!! 

    MyClass* myclass_ptr = new MyClass; 
    myclass_ptr->destroy(); 
} 

Lo que no entiendo es por eso que esto debería funcionar. ¿Por qué se llamaría al destructor al crear una instancia de MyClass?

+4

llamando a destrory() como este también le dará un error de compilación ya que está declarado privado –

+3

Me gustaría saber por qué quiere esto? – log0

+1

vea mi otra pregunta, que lo explica detalladamente: http: // stackoverflow.com/questions/3095856/prevention-unaligned-data-on-the-heap – eladidan

Respuesta

21

Cuando myclass llega al final de su alcance (el siguiente }) el compilador llama al destructor para liberarlo de la pila. Si el destructor es privado, sin embargo, no se puede acceder al destructor, por lo que la clase no se puede colocar en la pila.

No me gusta el aspecto de delete this. En general, creo que los objetos no deberían destruirse a sí mismos. Tal vez una mejor manera es tener un constructor privado para su clase y luego use una función estática para crear una instancia.

// In class declaration... 
static MyClass* Create() 
{ 
    return new MyClass(); // can access private constructor 
} 

// ... 

MyClass myclass; // illegal, cannot access private constructor 

MyClass* pMyClass = MyClass::Create(); 
delete pMyClass; // after usage 
+1

+1 - en lugar de jugar con destructores privados usando una variación del patrón singleton es la manera de hacerlo –

+15

@Holger: El único propósito de un singleton es permitir solo _una instancia, y esto no hace esto, por lo que __esto no es un singleton .__ _ Desearía poder votar por los comentarios._ – sbi

+0

+1 Bueno, usando un método de fábrica en lugar de piratear algo que podría no ser tan obvio para alguien que tiene que usar tu código. – fingerprint211b

12

¿Por qué el destructor se llama al crear una instancia de MyClass?

No lo es. Sin embargo, debe invocarse automáticamente cuando la instancia se sale del alcance. Si es privado, el compilador no debe generar ese código, de ahí el error.

Si cree que haciendo lo privado destructor es oscura, otra manera de restringir una clase para la asignación dinámica es hacer que todos los constructores privados y sólo tienen MyClass::create() funciones que devuelven los objetos asignados dinámicamente:

class MyClass { 
public: 
    static MyClass* create()    {return new MyClass();} 
    static MyClass* create(const Foo& f) {return new MyClass(f);} 
private: 
    MyClass(); 
    MyClass(const Foo&); 
}; 

Note que el regreso los indicadores desnudos de los objetos que deben borrarse están mal visto. Debe devolver punteros inteligentes lugar:

class MyClass { 
public: 
    static std::shared_ptr<MyClass> create()    {return new MyClass();} 
    static std::shared_ptr<MyClass> create(const Foo& f) {return new MyClass(f);} 
    // ... 
}; 
+1

-1 para "Si es privado, el compilador no debe generar ese código, ..." – berkus

+0

@Berkus: ¿Perdón? – sbi

+0

Si es privado, solo se puede llamar desde dentro del alcance de clase. No significa que el compilador debe o no generar código. – berkus

1

instancia Porque cuando sale del ámbito, que tiene que ser destruido mediante destructor. Puntero a instancia no hace esto.

1

Cuando una variable local se sale del alcance, se destruye. Y en la destrucción, se llama destructor de objeto. Aquí, el alcance es de función principal. Cuando el programa sale, el destructor del objeto myclass se llamará

1

No lo es. El compilador intenta llamar al destructor cuando sale del alcance e indica la línea de código que produce este efecto, que es mucho más útil que señalar al final de la función.

+0

Esto debería ser un comentario (no responde la pregunta (principal)). Lo mismo para Pardeep arriba. – n1ckp

+1

La pregunta era "¿Por qué se llamaría al destructor al crear una instancia de MyClass?". Esta es una respuesta a esa pregunta. Aprende a leer primero. – berkus

+1

@Berkus ¿eh? La pregunta en el título es "C++, evitando que se cree una instancia de clase en la pila (durante la compilación)". Lo siento pero esto NO responde esa pregunta. – n1ckp

Cuestiones relacionadas