2010-10-18 17 views
9

El siguiente código compilado con MSVC9.0 se ejecuta y genera Destructor cuatro veces, lo cual es lógico.Suicidio orientado a objetos o eliminar esto;

#include <iostream> 
class SomeClass 
{ 
public: 
    void CommitSuicide() 
    { 
     delete this; 
    } 
    void Reincarnate() 
    { 
     this->~SomeClass(); 
     new (this) SomeClass; 
    } 
    ~SomeClass() 
    { 
     std::cout << "Destructor\n"; 
    } 
}; 

int main() 
{ 
    SomeClass* p = new SomeClass; 
    p->CommitSuicide(); 
    p = new SomeClass; 
    p->Reincarnate(); 
    p->~SomeClass(); //line 5 
    p->CommitSuicide(); 
} 

creo que las primeras 4 líneas de código, en el principal no dan como resultado un comportamiento indefinido (aunque no del todo seguro de lo delete this;). Me gustaría tener una confirmación 0 < marcador de posición para el antónimo de confirmación> de eso. Pero tengo serias dudas sobre las líneas 5 y 6. Se permite llamar explícitamente al destructor, ¿no es así? Pero, ¿se considera que la vida útil del objeto finalizó después de eso? Es decir, ¿la invocación de otro miembro después de la llamada explícita del destructor está permitida (definida)?

En resumen, ¿qué partes del código anterior (si corresponde) dan como resultado un comportamiento indefinido (técnicamente hablando)?

+0

Pero el constructor solo se llama 3 veces, entonces, ¿cómo se llama lógico al destructor 4 veces? Sería una bomba tan pronto como la clase obtenga miembros de datos (no triviales). – visitor

+0

- se llama "denegación" – slashmais

Respuesta

2

p-> ~ SomeClass(); // línea 5

p-> CommitSuicide(); // línea 6

La línea (6) invoca definitivamente Comportamiento indefinido.

Es decir, ¿es la invocación de otro miembro después de la llamada explícita del destructor permitido (definido)?

No! Tu suposición es correcta.

+0

línea 6 "debería" dar un error de acceso a memoria (segfault en Linux) porque el espacio de direcciones previamente ocupado por la instancia de SomeClass apuntada por p, "debería" haber sido liberado adecuadamente por el sistema operativo. ¿O el destructor hace una llamada tardía para eliminar? – slashmais

+0

@slashmais: No, no hay tal garantía, y muy pocas implementaciones funcionan así. La mayoría de las implementaciones tienen una noción de "espacio libre", que es la memoria asignada por el sistema operativo al programa, pero que no contiene ningún objeto. La memoria recuperada de objetos eliminados se recicla en este "espacio libre" para ser utilizada por objetos futuros. – MSalters

+0

Sí, pensé que sería algo así. Explica la línea 6 y luego porque el espacio no se ha reciclado todavía. – slashmais

6

El delete this; está bien. La última p->CommitSuicide(); proporciona un comportamiento indefinido porque ya destruyó el objeto en la "línea 5".

0

"delete this" está bien siempre que no intente llamar a ningún código de ese objeto después de la eliminación (ni siquiera el destructor). Por lo tanto, un objeto de eliminación automática solo debe colocarse en el montón y debe tener un destructor privado para protegerlo de la creación en la pila.

No sé si una llamada directa al destructor conduce a un comportamiento indefinido, pero un operador de eliminación definido por el usuario no se ejecutará.

Cuestiones relacionadas