2010-10-18 9 views
9

Il seguente codice compilato con MSVC9.0 esegue e produce Destructor quattro volte, il che è logico.Suicidio orientato agli oggetti o cancellarlo;

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

penso che le prime 4 righe di codice in principale non portano a comportamento non definito (anche se non del tutto sicuro della delete this; cosa). Vorrei avere una conferma o < segnaposto per l'antonio di conferma> di quello. Ma ho seri dubbi sulle linee 5 e 6. È permesso chiamare esplicitamente il distruttore, non è vero? Ma la vita dell'oggetto considerato è terminata dopo? Cioè, l'invocazione di un altro membro dopo la chiamata esplicita del distruttore è consentita (definita)?

Per riassumere, quali parti del codice precedente (se presenti) comportano un comportamento non definito (tecnicamente parlando)?

+0

Ma il costruttore viene chiamato solo 3 volte, quindi come si chiama il distruttore 4 volte logico? Bombarderebbe non appena la classe riceve (non banali) membri dei dati. – visitor

+0

- si chiama "rifiuto" – slashmais

risposta

2

p-> ~ SomeClass(); // line 5

p-> CommitSuicide(); // line 6

Line (6) invoca sicuramente il comportamento non definito.

Ovvero, è l'invocazione di un altro membro dopo la chiamata esplicita del distruttore consentito (definito)?

No! La tua ipotesi è corretta.

+0

riga 6 "dovrebbe" dare un errore di accesso alla memoria (segfault su linux) perché lo spazio indirizzo precedentemente occupato dall'istanza di SomeClass puntata da p, "dovrebbe" essere stato liberato correttamente dal sistema operativo. O il distruttore fa una chiamata ritardata per cancellare? – slashmais

+0

@slashmais: No, non c'è una tale garanzia e pochissime implementazioni funzionano così. La maggior parte delle implementazioni ha una nozione di "spazio libero", che è la memoria allocata dal sistema operativo al programma, ma che non contiene alcun oggetto. La memoria recuperata dagli oggetti cancellati viene riciclata in questo "spazio libero", per essere utilizzato da oggetti futuri. – MSalters

+0

Sì, pensavo che sarebbe stato qualcosa del genere. Spiega la linea 6 che ha avuto successo perché lo spazio non è stato ancora riciclato. – slashmais

6

Il delete this; va bene. L'ultimo p->CommitSuicide(); fornisce un comportamento indefinito perché hai già distrutto l'oggetto nella "riga 5".

0

"elimina questo" è ok se non si tenta di chiamare alcun codice di quell'oggetto dopo l'eliminazione (nemmeno il distruttore). Quindi un oggetto autoeliminante deve essere posto solo nell'heap e avere un distruttore privato per proteggerlo dalla creazione nello stack.

Non so se una chiamata diretta al distruttore porta a un comportamento non definito, ma un operatore delete definito dall'utente non verrà eseguito.