2009-12-07 16 views
19

Stavo leggendo questo article e voleva così la gente consiglio:Dovrebbe essere chiamato "delete this" da un metodo membro?

D: Dovrebbe delete this; essere chiamata dall'interno di un metodo di membro?

+7

Una domanda ancora migliore "Si dovrebbe mai usare 'cancellare questo'"? Risposta - no. –

+13

Ci sono rare occasioni in cui è appropriato chiamare "elimina questo" - ma sono molto rari ... –

+2

@Neil: non puoi usare "cancella questo" in nessun'altra parte che non sia una funzione membro (o un inizializzatore in un costruttore, Immagino, ma mi fa male il cervello). Quindi dovresti postarlo totalmente come risposta. –

risposta

33

Normalmente questa è una cattiva idea, ma a volte è utile.

È perfettamente sicuro fino a quando non si utilizzano variabili membro dopo aver eliminato e finché i client che chiamano questo metodo capiscono che potrebbe eliminare l'oggetto.

Un buon esempio di quando questo è utile è se la classe utilizza il conteggio dei riferimenti:

void Ref() { 
    m_References++; 
} 

void Deref() { 
    m_References--; 
    if (m_References == 0) { 
    delete this; 
    } 
} 
+3

come si scrive "puntatori penzolanti"? – elcuco

+16

Hai appena scritto bene, Elcuco. Qual è il tuo punto? Hai paura che un oggetto che si distrugge creerebbe più puntatori penzolanti di quanto sarebbe se qualcos'altro distruggesse l'oggetto? 'foo-> Deref()' non è peggio di 'if (foo-> Deref() == 0) elimina foo;'. Inoltre, se il conteggio dei riferimenti è zero, allora non ci sono altri puntatori da lasciare a penzolare comunque. –

1

Non senza una buona ragione per farlo.

Il problema è che quando si chiama delete this in una funzione membro, si sta creando un brutto effetto collaterale: il chiamante ha ancora un riferimento all'istanza che ora è completamente non valida.

Questo probabilmente non è un comportamento previsto, quindi potrebbe facilmente portare a bug sgradevoli.

Detto questo, ci sono momenti in cui questo è appropriato (ho visto alcuni schemi di gestione della memoria, con determinate librerie, in cui si creano esplicitamente metodi nelle classi che si cancellano - principalmente per l'interoperabilità linguistica). In generale, penso che sia una cattiva pratica, però.

12

Penso che ci sono davvero 2 domande qui

possibile eliminare questo essere chiamato validamente da un metodo membro ?

Sì. Questo è legale finché si è molto attenti con l'uso.

L'eliminazione deve essere utilizzata all'interno di un metodo membro?

In casi molto specifici questo è necessario. Alcuni tipi di puntatori intelligenti, ad esempio, utilizzano il modello delete this per eliminare il puntatore. Esempi: stile CComPtr<>.

Oltre ai puntatori intelligenti, dovrebbe essere evitato a meno che non si abbia una buona ragione per farlo. Anche allora, vorrei riconsiderare attentamente il mio scenario e vedere se c'era un modo per aggirarlo.

5

Sì, ci sono alcuni casi in cui è comune.

conteggio Riferimento:

void release() 
{ 
    cnt--; 
    if (cnt == 0) 
    delete this; 
} 

programmazione GUI. In alcuni framework, quando un utente chiude una finestra, è normale che la finestra si elimini.

11

Sì, è possibile e here's una buona spiegazione di quando e perché

+1

O qui c'è un collegamento che spiega il pericolo e la lettura tra le righe del perché non dovresti farlo. –

0

Si può fare, a condizione propria l'ultimo elemento in una funzione membro, e che dopo il ritorno si dimenticano che oggetto mai esistito .... ma si, come l'articolo chiede ... Perché vorresti farlo?Non so cosa dice lo standard, ma mi dà una sensazione strana: P

Immagino che questo è un po 'come se dovessi usare una dichiarazione GOTO, e io personalmente uso GOTO per ripulire le risorse in C a volte, specialmente in condizioni eccezionali.

mi chiedo quali sono le implicazioni stato condiviso sono (dichiarazione sfocata lo so): P

1

Alcune librerie di threading usano in sede di attuazione un auto distruggere al termine thread.

void Thread::threadFunc() 
{ 
    doRun(); 

    if(this->destroyOnExit == true) 
     delete this; 
} 
1

Questo è stato spesso utilizzato nei giorni MFC. IIRC l'ultimo messaggio di una finestra riceve è WM_NCDESTROY, a quel punto si potrebbe chiamare delete this, supponendo che tu fossi una qualche forma di sadico naturalmente (anche se MFC stesso ha fatto questo a volte penso.)

+1

Sì, la funzione OnDestroy() di MFC lo fa :) –

5

Tutto pronto per i voti verso il basso.

dovrebbe: No.
Can tecnicamente: Sì
E 'una buona idea: Assolutamente no.
Ci sono situazioni che è utile: Naturalmente. Se sei C++ foo è estremamente forte. Ma la maggior parte delle persone non è così brava. Quindi fallo solo se hai un team di persone che lavorano con te in grado di fare una revisione decente del codice.

Perché:
Non c'è modo per un oggetto di sapere che è stato allocata dinamicamente (e deve quindi eliminare) o è un oggetto normale (e quindi non deve essere cancellato) e, quindi, come può esso decidide tempo dovrebbe essere cancellato. Quindi se un oggetto si sta cancellando, a mio parere c'è qualcosa di terribilmente sbagliato nel design.

Se si dispone di un oggetto che deve essere gestito, è necessario scrivere un oggetto seprate per la gestione (quindi indicatori intelligenti). Lascia che l'oggetto faccia ciò che è buono, quindi separi la gestione dell'oggetto in un altro oggetto.

+0

Si noti inoltre che "al di fuori della classe" non si può ancora essere sicuri che un puntatore punta realmente su un oggetto assegnato dinamicamente e non su un oggetto automatico o statico, ad esempio. (In effetti penso che in molti casi si possa essere anche meno sicuri della funzione membro ...) Quindi 'delete p' è rischioso indipendentemente dal fatto che' p' sia 'this' o no. –

+0

@Adam: Grazie. Ma come sottolineato, "può" essere utile. Ma nel C++ moderno è considerata una pratica migliore per separare la gestione dell'oggetto dall'implementazione dell'oggetto (quindi i puntatori intelligenti vengono ora utilizzati anziché COM). Si noti inoltre che un oggetto di gestione può facilmente garantire che l'oggetto che gestisce viene assegnato dinamicamente in modo che sia completamente una premessa sbagliata. –

0

Sì. Come tutte le risposte dicono, se sei sicuro al 100% che i dati della classe non saranno utilizzati dopo che è stato chiamato lo delete this.

Ad esempio, in un progetto:

void Test() 
MyClass * Someclass = new MyClass; 
SomeClass->DoYourThing(); 
SomeClass->KillYourself(); 
return; 

void MyClass::DoYourThing() { return; } 
void MyClass::KillYourself() {delete this;} 

spiegazione molto semplice, il progetto utilizzato delete this; nell'ambito della gestione della memoria per oggetti di quel tipo; il loro costruttore li ha aggiunti ad una lista privata di classi di quel tipo in uso, e si sono tolti da quella lista quando sono stati distrutti e poi cancellati (questo non era in un distruttore). Tutti gli oggetti di quella classe che non si erano eliminati quando il programma ha raggiunto il suo endpoint poi tutti avevano il loro equivalente KillYourself() chiamato da una funzione di membro static CleanYourselves()

0
  1. delete this non può essere chiamato da una funzione non membro :)
  2. È una cattiva idea farlo finché non capisci le sue conseguenze.
0

Anche se non direttamente correlato a questo thread, volevo chiarirlo. mi è stato chiesto una domanda che, data una situazione:

int* a = new int ; 
int* b = a ; 
delete a; 

Ora è la dichiarazione successiva al sicuro?

cout<<*b ;

La mia risposta: Dopo eliminare una, la posizione indicata dal un è stato contrassegnato per l'eliminazione e in qualsiasi punto del tempo che può essere assegnato a qualche altro oggetto. Quindi l'accesso al valore utilizzando b non è sicuro in quanto potrebbe essere modificato dopo essere stato assegnato a un altro oggetto.

Nota: No downvoting per favore, questo è solo un chiarimento

Problemi correlati