2012-02-08 11 views
6

In Delphi 5, ho attualmente scritto il codice che chiama Free su più variabili in un blocco finally, ad es.In Delphi 5, può mai sollevare un'eccezione?

... 
finally 
    a.Free; 
    b.Free; 
    c.Free; 
end; 

Questo codice presuppone che Free può mai aumentare, dal momento che se, ad esempio, a.Free sollevato, la memoria per b e c sarebbe trapelato. Questa ipotesi è giustificata?

+0

Perché il downvotore di interesse? È una domanda chiara, non c'è ambiguità e volevo sinceramente conoscere la risposta. * Shrug * –

+0

Penso che tu abbia accettato una risposta qui troppo veloce. – NGLN

+0

@NGLN: Accetto davvero (scusate TOndrej), penso che la risposta di David sia molto meglio. –

risposta

10

Il metodo Free non genera esplicitamente un'eccezione, ma chiama il distruttore virtuale Destroy che sicuramente potrebbe generare un'eccezione.

Quindi, se si vuole essere sicuri che tutti gli oggetti vengono distrutti, anche se uno dei distruttori solleva un'eccezione si finisce con codice come questo:

a := TMyObject.Create; 
try 
    b := TMyObject.Create; 
    try 
    ... 
    finally 
    b.Free; 
    end; 
finally 
    a.Free; 
end; 

Detto questo, dovrebbe essere un principio di progettazione che non si generano eccezioni in un distruttore. Quindi, a mio avviso, è perfettamente ragionevole considerare il punto di vista secondo cui se viene sollevata un'eccezione in distruttore, il tuo programma viene praticamente bloccato. La perdita di oggetti a quel punto non è qualcosa di cui preoccuparsi. Se il tuo distruttore ha sollevato un'eccezione, probabilmente stai già perdendo perché quel distruttore non è stato eseguito fino al completamento.

Quindi, a mio parere, può essere perfettamente ragionevole raggruppare alcune chiamate a Free e, naturalmente, si evita di nidificazione try/finally che è qualcosa vale la pena lottare per.

Se si desidera solo un try/finally poi ricordare a scrivere il codice come questo:

a := nil; 
b := nil; 
try 
    a := TMyObject.Create; 
    b := TMyObject.Create; 
    ... 
finally 
    b.Free; 
    a.Free; 
end; 

Nella mia base di codice Ho alcuni metodi di supporto che rendono questo più pulito.Poi il codice può assomigliare a questo:

InitialiseNil(a, b); 
try 
    a := TMyObject.Create; 
    b := TMyObject.Create; 
    ... 
finally 
    FreeAndNil(b, a); 
end; 

ho dato il mio FreeAndNil lo stesso nome della funzione in SysUtils che a prima vista può sembrare strano, ma è sicuro e benigna per farlo. Naturalmente questi aiutanti entrano in gioco quando hai anche più di due oggetti.

+0

+1 ottima risposta, grazie. –

3

Dipende da ciò che accade nel distruttore.

+0

Completamente corretto, ho cancellato il mio anser sbagliato. Non ha preso in considerazione i distruttori. Ecco perché i distruttori non dovrebbero lanciare eccezioni. – jpfollenius

0

Naturalmente FREE può emettere eccezioni, quindi sì, si perde memoria nel codice se A.FREE emette un'eccezione, B.FREE e C.FREE non verranno chiamati.

La domanda è: vuoi gestire le eccezioni o lasciarle accadere? Dipenderà da cosa sarà il tuo codice, altri sviluppatori lo useranno (per esempio). Per evitare perdite di memoria, è necessario nidificare le sezioni try..finally;

a:=tobject.create; 
try 
    b:=tobject.create; 
    try 
    c:=tobject.create; 

    ... 

    finally 
    c.free; 
    end; 
finally 
    b.free; 
end; 
a.free; 

Ordinamento. È una domanda su cosa sta facendo il tuo codice in realtà se dovessi anche racchiudere il A.FREE in una sezione try..finally anche se penso che probabilmente dovresti.

+3

Il tuo 'a.free;' è al di fuori di qualsiasi 'try'..'finally', e tu provi a liberare' b' se 'b: = tobject.create; 'solleva un'eccezione (uguale a' c'). – hvd

+1

Inoltre, se 'c.free' solleva un'eccezione, hai ancora una perdita perché non hai effettivamente liberato' c'. – hvd

+0

È discutibile che questo sia comunque un buon stile di codifica, ma ho detto che probabilmente dovresti provare anche..finalmente anche a.free; Stavo solo dimostrando come è possibile farlo :-) –

1

se il vostro a.free genera un'eccezione, a (a seconda di quanto il distruttore si è liberato dai campi dell'oggetto a), gli oggetti b e c avranno perdite perché l'esecuzione sarà interrotta. Ad ogni modo, qualcosa è sbagliato nel tuo distruttore, se solleva un errore. quindi, dovresti proteggere il codice con try..finally blocks, ma IMHO dovresti verificare che i distruttori non ti diano errori di circostanza.

+2

L'ipotesi di Stuart è "Free non può sollevare un'eccezione", e chiaramente può. –

+0

@FrankShearar. Grazie, ho corretto la risposta. – RBA

+1

Non dimenticare, anche l'oggetto 'a' perde se il suo distruttore solleva un'eccezione. – hvd

2

Ci potrebbero essere 2 cose che possono causare SomeObj.Free a sollevare un'eccezione:

  1. un'eccezione non gestita in distruttore della SomeObj istanza della classe o il suo antenato.
  2. Riferimento di classe non valido a causa della variabile non inizializzata SomeObj.

Nel tuo caso, se a.Free solleva un'eccezione per uno dei motivi di cui sopra, ci sarebbe stata una perdita di memoria per oggetto b e c e magari un po 'di perdite all'interno oggetto a a causa di un'eccezione non gestita in distruttore.

Problemi correlati