2010-03-31 12 views
11

Per quanto ne so, in caso di un'eccezione non rilevata, C++ distrugge immediatamente le variabili locali, Java rilascia i riferimenti e lascia il resto per il garbage collector.Java e C++ on Stack Problema di srotolamento

È giusto? Qual è esattamente la differenza tra Java e C++ su questo problema? in altre parole, quale di queste due lingue è considerata migliore in termini di problematiche legate allo stack? :)

+3

Soggettivo: definire "migliore". – razlebe

+0

Java implementa un vero garbage collector, quindi in teoria non dovresti mai preoccuparti di un oggetto che non distrugge tutto ciò che crea sullo stack. Il C++ presume che tu stia attento. – thecoshman

+4

Java implementa un _memory_ garbage collector. Di conseguenza, i file temporanei non vengono raccolti e possono essere trapelati da una pila. D'altra parte, nello stack C++ si sganciano i distruttori di chiamate, che oltre alla pulizia della memoria possono anche ripulire file temporanei e altre risorse. Quindi Java è più semplice e C++ più flessibile, un compromesso di progettazione standard. – MSalters

risposta

5

Lo srotolamento dello stack chiama in modo specifico i distruttori di tutti gli oggetti completamente costruiti nella catena di chiamate fino al punto in cui viene rilevata l'eccezione.

Java semplicemente non ha uno stack che si slega, non fa nulla agli oggetti se viene lanciata un'eccezione. Devi gestire personalmente gli oggetti nei blocchi catch e finally. Questo è principalmente il motivo per cui C# ha introdotto using statements - semplificano la chiamata a IDisposable.Dispose(), ma ancora una volta non è la sostituzione completa dello stack di C++ che si svolge.

+0

Per porre la domanda qui potrebbe essere meglio: perché Java non ha un meccanismo simile a un distruttore che viene chiamato quando il garbage collector raccoglie l'oggetto? In questo modo, garantiremmo la chiusura delle nostre risorse; non importa quando, dal momento che siamo interessati più a gestire le perdite di memoria. – Feyyaz

2

Si è proprio corretto, C++ distrugge tutte le variabili locali, nell'ordine inverso, in quanto esce da ciascuna funzione nello stack, proprio come se si stesse eseguendo il ritorno a livello di codice, e da main().

9

ho intenzione di ottenere fiammato per questo, ma ...

C++ è senza dubbio meglio di Java nello stack rilassarsi davanti - non c'è proprio nessun concorso. I distruttori di oggetti C++ sparano su tutta la pila fino al raggiungimento del punto di cattura, rilasciando tutte le risorse gestite con grazia lungo la strada.

Come hai detto, Java lascia tutto questo in balia del garbage collector non deterministico (nel caso peggiore) o nelle mani di qualsiasi blocco finalmente creato appositamente per il codice (dal momento che Java non lo fa supporta il vero RAII). Cioè, tutto il codice di gestione delle risorse è nelle mani dei clienti di ogni classe, piuttosto che nelle mani del progettista di classe dove dovrebbe essere.

Detto questo, in C++, il meccanismo di srotolamento dello stack funziona correttamente solo se si fa attenzione a garantire che i distruttori stessi non emettano eccezioni. Una volta che hai due eccezioni attive, il tuo programma abort() è senza passare (e ovviamente senza sparare a nessuno dei rimanenti distruttori).

+0

In C++ gli oggetti creati nello stack ottengono il richiamo del distruttore, ma ciò non accade per gli oggetti sull'heap, a cui fa riferimento un puntatore con una variabile locale. – Mnementh

+1

@Mnementh: ad eccezione degli oggetti heap che appartengono correttamente a un oggetto con un distruttore. – quamrana

+0

@quamrana: Sì, come ho spiegato nella mia risposta. – Mnementh

2

Per lo stack fare lo stesso: rilasciano lo stack per i blocchi che si lasciano con l'eccezione. In Java tutti i tipi primitivi (int, double ecc.) Vengono salvati direttamente, le variabili locali di questo tipo vengono rilasciate in questo momento. Tutti gli oggetti vengono salvati tramite riferimenti in variabili locali, quindi i riferimenti vengono rimossi, ma gli oggetti rimangono nell'heap. Se questo era l'ultimo riferimento all'oggetto, vengono rilasciati nella successiva garbage collection. Se in C++ gli oggetti sono creati sull'heap e le variabili locali mantengono un puntatore, gli oggetti sull'heap non vengono rilasciati automaticamente, rimangono nell'heap per sempre (sì, si ottiene una PERDITA DI MEMORIA). Se sono stati salvati oggetti nello stack, viene chiamato il distruttore (e potrebbe rilasciare altri oggetti di riferimento nell'heap).

+2

Vero, ma i puntatori intelligenti in C++ consentono di distruggere automaticamente anche gli oggetti allocati su heap. – sharptooth

+0

Giusto, i puntatori intelligenti funzionano in modo diverso. – Mnementh

+2

Infatti funzionano esattamente allo stesso modo. Stack di sbobinamenti chiama i loro distruttori e, a loro volta, i loro distruttori distruggono i corrispondenti oggetti allocati nell'heap. – sharptooth