Newsgroup: it.comp.lang.visual-basic
Titolo: Differenza tra l'evento "Unload" e "Terminate"

in realtą mi sento molto stupido a fare questa domanda ma non solo questa
domanda anche altre che vi ho fatto precedentemente. Mi sto rendendo conto
che so un centesimo di visual basic e visto che voglio lavorare nel mondo
dell'informatica non mi pare un bell'inizio comunque mi potete spiegare in
un esempio molto pratico di differenza tra l'unload e l'evento terminate.
Grazie P.S. scusate lo sfogo.
--------------------------------
Inviato via 
http://usenet.libero.it

 tra l'unload e l'evento terminate. Grazie P.S. scusate lo sfogo.
Per come li intendo io, Unload viene chiamato quando un form viene scaricato
dalla memoria, quindi può essere richiamato più volte.
Terminate, invece, viene richiamato solo quando il programma raggiunge
l'End.
Ciao
Andrea

 ha scritto nel messaggio
news:gDQN9.26392$R45.1...@news2.tin.it...

Il Terminate e' da intendersi riferito alla classe "pura", mentre l'Unload
e' relativo principalmente alla controparte grafica della form.
Le form definite in design sono classi auto-istanzianti (diciamo
l'equivalente di quello che ottieni con Dim a As New Classe), ma per il
resto possono essere trattate allo stesso modo di quelle comuni, il
terminate quindi si comporta esattamente come l'evento Class_Terminate,
viene scatenato quindi quando non esiste piu' alcun riferimento all'istanza
corrente; tanto per capirci prova a incollare in una form questo codice
Private Sub Form_Unload(Cancel As Integer)
Debug.Print "Unload"
End Sub
Private Sub Form_Terminate()
Debug.Print "Terminate"
End Sub
e da un'altra parte a eseguire questo codice:
'viene richiamata l'istanza implicita di Form1 e applicato
'il metodo Show, che a sua volta invoca il Load se necessario
Form1.Show vbModal
'l'istanza di default viene distrutta
Set Form1 = Nothing
'il nuovo riferimento alla variabile Form1 fa si che l'istanza
'venga ricreata automaticamente
Form1.Show vbModal
nota adesso come, dopo aver chiuso per due volte la form in questione,
l'output nella finestra di debug sia
Unload
Terminate
Unload
Ciao
--
Luca Dormio - 
luca....@tin.it
________________________________
"Marty, non stai ragionando in maniera quadridimensionale"
Dr. Emmett L. Brown

 wrote in message
news:gDQN9.26392$R45.1...@news2.tin.it...

---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (
http://www.grisoft.com
).
Version: 6.0.426 / Virus Database: 239 - Release Date: 02/12/2002

 un esempio molto pratico di differenza tra l'unload e l'evento terminate.
molto rapidamente:
quando si scarica dalla memoria un form, vengono scatenati in successione questi tre
eventi:
1) QueryUnload
2) Unload
3) Terminate
Le principali differenze dovrebbero essere:
Il primo evento dà la possibilità di "arrestare il processo", oltre ad informarti di chi è
che "chiede" lo scaricamento del form.
Il secondo evento ti consente comunque di annullare la chiusura, solo che, a detta
dell'help, non impedisce la chiusura del sistema operativo.
Il terzo evento non può essere annullato, inoltre viene scatenato quando sono già stati
"scaricati" tutti i controlli contenuti nella form, quindi qualsiasi riferimento ad essi
all'interno di questa routine produrrà un errore di run time.
Salutoni
Sergio

 l'evento unload e l'evento terminate quindi non vedo ambiguita'.
Il form li implementa entrambi :)
Proprio perchč un form *č* una classe.
Si verificano in due condizioni diverse:
Load Form1           ' Initialize, Load (Carica il codice e gli oggetti
relativi)
Unload Form1         ' Unload (Scarica il form e gli oggetti associati)
Set Form1 = Nothing  ' Terminate (scarica completamente il codice del form
                     ' - il form non esiste piů)
Ciao
--
using System.Gtk.Forms = "
http://www.neodatatype.net/windowsforms/sgf.aspx
"
mathParser = "
http://www.neodatatype.net
"
sitoComune = "
http://www.it-lang-vb.net
"


[SNIP]
Come accennavo nell'altro messaggio, devi specificare pero' esattamente cosa
intendi per "scaricare dalla memoria".
E' importante perche', magari per te e' implicito, ma nella maggior parte
dei casi si intende semplicemente "Unload <form>", in questo caso l'ultimo
evento non viene scatenato in quanto si e' scaricato dalla memoria il form
ma non si e' distrutto il riferimento alla *istanza di classe* form
Viceversa le istruzioni
Unload <form>
Set <form> = Nothing
danno luogo agli eventi indicati, ma va notato che non sono necessariamente
conseguenti (potrei caricare/scaricare piu' volte il form senza mai
distruggere l'istanza, e fare il Set=Nothing solo alla fine)


 distruggere l'istanza, e fare il Set=Nothing solo alla fine)
E' importante notare (anche per capire meglio l'utilità dei due eventi) che
in questo caso le variabili pubbliche di un form mantengono il loro valore
dopo i vari unload.
Solo con il Set = Nothing tutto il codice viene scaricato e quindi si può
ricominciare con un form "nuovo" al prossimo Load.


 dopo i vari unload.
Esatto, e questo vale non solo per le pubbliche ma anche per quelle
*private* definite a livello di form
Per chi ha vecchi retaggi VB3 ad esempio questo comportamento all'inizio non
e' immediato, ma diventa subito facile da capire se, come hai fatto notare
nell'altro messaggio, ci si abitua a considerare il Form come una classe
vera e propria


 *private* definite a livello di form
Stavo per scrivere un post con richiesta di chiarimenti per questa frase....
poi ho fatto mente locale sul "definite a livello di form"...
La sostanza, alla fine, è: una classe non viene distrutta fino a che non viene
esplicitamente impostato a nothing l'ultima variabile che fa riferimento ad essa, oppure
in modo implicito quando l'ultima variabile viene distrutta perchè uscita dall'area di
visibilità.
Quindi, nel caso di una variabile dichiarata a livello di form, fino a che non viene
distrutta l'istanza del form medesimo....
Direi che i conti tornano.
Salutoni
Sergio

 Sergio
Andrea


forse č un dettaglio, ma mi pareva stessimo parlando di vb6, e vb6 non prevede il
meccanismo della raccolta rifiuti.
Salutoni
Sergio

 meccanismo della raccolta rifiuti.
Come no? :)
Chi credi che pensi a rilasciare la memoria di un oggetto quando tutti i
riferimenti sono a nothing?
E quando ti dimentichi di settarlo a nothing?
E tutti gli array di cui non fai un Erase quando non ti servono piů?


 Come no? :)
(snip)
chiedo venia, avevo sempre inteso che con la locuzione Garbage Collection ci si riferisse
a quel imho perverso meccanismo con cui 
vb.net
 e c# gestiscono il rilascio delle risorse
impegnate dagli oggetti non piů utilizzati. Se essa ha anche altri significati lo imparo
in questo momento
Salutoni
Sergio

 significati lo imparo in questo momento
Il significato č quello "letterale": raccolta della spazzatura
(qui diremmo rumenta...) che sta ad indicare che č il
runtime dell'ambiente ad occuparsi della "liberazione" della
memoria allocata e non il programmatore.
Poi vi sono *molti* modi di implementare questo meccanismo.
Ciao.
-- 
BSD is for UNIX lovers -- linux is for Windows haters.

 Sergio
Ciao
Andrea

 Redmond a suon di dollaroni...
Lo ha detto, lo ha detto... e più volte...


 Ciao.
Ciao
Andrea

 la fa passare per una feature...
Per esserlo lo è certamente, non si può certo mettere in dubbio.
Non è una caratteristica positiva.
Ed anche Java la fa passare per caratteristica positiva... ed i
programmatori Java se la bevono...


 in questo momento
No, ha esattamente lo stesso significato.
Non vedo nessuna differenza tra VB6 e .net leggendo la tua prima frase.


 Non vedo nessuna differenza tra VB6 e .net leggendo la tua prima frase.
Insisto, non per cocciutaggine ma perchè voglio chiarirmi le idee.
Leggendo il libro di balena sul 
vb.net
, ho inteso che in questo linguaggio la liberazione
delle risorse utilizzate dalle variabili/oggetti non più utilizzati non avviene
"immediatamente", quando l'oggetto viene impostato a nothing o quando esce dallo scope, (a
meno che non venga invocato esplicitamente il metodo dispose, se non ricordo male), ma
solo se si esauriscono le risorse disponibili, nel qual caso viene scatenato il meccanismo
della garbage collection.
Mi sembra invece che nel vb6 non esista questo parcheggio delle risorse: nel momento
stesso in cui un oggetto viene distrutto (implicitamente o esplicitamente) le risorse
vengono liberate, ed in particolare viene eseguito il codice di "terminate" della classe.
Mi sembra insomma che tra i due sistemi si ha la differenza che in vb6 si sa "esattamente"
quando viene "terminato" un oggetto, mentre con .net ciò può accadere in un qualsiasi
momento posto tra la distruzione della variabile e la terminazione dell'applicazione.
Questo è in breve quello che ho capito, se le cose non stanno così ogni precisazione è
benvenuta (molto benvenuta)
Salutoni
Sergio

Questo č in breve quello che ho capito
A dire il vero l'ho capita cosi' anch'io, anzi mi pare d'aver pure
capito che la memoria possa essere liberata anche _dopo_ la fine dell'
applicazione.
-- 
ciao, hal

 così ogni precisazione è benvenuta (molto benvenuta)
In VB6 c'è un meccanismo di reference counting, che è comunque
un sistema di GC. 
Prova:
<code>
'file pippo.cls
public sub class_terminate()
    msgbox "Pippo dtor"
end sub
'file form1.frm con un command button
dim a as pippo
private sub command1_click()
    dim b as pippo
    set b = new pippo
    set a = b
    set b = nothing
end sub
</code>
Prova a vedere se il "set b = nothing" e/o l'uscita dallo scope
hanno l'effetto sperato, ovvero quello di distruggere l'oggetto
b e di richiamare class_terminate.
Questo porta ad un grosso problema del reference counting. In
caso di dipendenze circolari (a possiede un riferimento a b che
possiede un riferimento ad a) non c'è possibilità di distruggere
gli oggetti interessati.


 gli oggetti interessati.
ok, mi sono dimenticato di specificare "quando viene distrutto _l'_ultimo_riferimento",
con il conseguente problema dell'impossibilità di azzerare il conteggio delle referenze
quando ci sono i riferimenti circolari.
Ma, a parte questo dettaglio (di non secondaria importanza, lo ammetto), mi pare di aver
capito due cose:
1) anche il meccanismo di "distruzione automatica" degli oggetti utilizzato da vb6 può
essere chiamato garbage collection
2) le considerazioni sulla diversa tempistica della garbage collection in vb6 rispetto a
vb.net
 sono (più o meno) quelle che ho elencato precedentemente
A questo punto mi sorge una domanda/curiosità piuttosto OT:
credo di aver capito che il c++ non utilizzi alcun tipo di garbage collection: è così?
come si regola in merito alla distruzione degli oggetti: deve essere sempre fatta in modo
esplicito da codice?
Salutoni & auguri
Sergio

 essere sempre fatta in modo esplicito da codice?
In C++ ci sono tre tipologie di allocazione degli oggetti:
allocazione statica (che non ci interessa in questo contesto),
allocazione dinamica (sullo heap) ed automatica (sullo stack).
In VB (6, .NET), in Java, C#, ed altri, gli oggetti sono
allocati *tutti* solo dinamicamente (sullo heap).
In C++ gli oggetti dinamici devono essere *esplicitamente*
distrutti, mentre gli oggetti automatici (come suggerisce la
parola) vengono distrutti automaticamente:
<code>
class Pippo {...};
void fai_qualcosa()
{
    Pippo* p = new Pippo; //allocazione dinamica
    Pippo p1; //allocazione automatica
    //...  uso p e p1
    delete p; // distruggo p
    // p1 viene distrutto automaticamente all'uscita dallo scope
}
</code>
Se nel codice che utilizza p e p1 venisse sollevata un
eccezione, verrebbe distrutto il solo p1, perché si
uscirebbe dalla funzione *prima* del delete p) e quindi verrebbe
richiamato il solo distruttore di p1 con il conseguente mancato
rilascio delle risorse allocate da p.
Questo, in aggiunta alla possibile dimenticanza dei delete, crea
la "famosa" difficoltà di utilizzo dei puntatori, che viene
presa a pretesto per giustificare l'introduzione della GC in
altri linguaggi. In realtà il C++ offe altri meccanismi che non
presentano gli effetti collaterali della GC


 la terminazione dell'applicazione.
A parte la tempistica il concetto è lo stesso.
In .NET non è necessario distruggere gli oggetti poichè ci pensa la GC
quando ne ha voglia.
Personalmente non mi piace molto questo sistema, poichè non si sa mai quando
un oggetto esiste ancora, quando (e spero sia solo una mia lacuna) un
oggetto è usato per riferimento e quando per valore (e quindi senza sapere
se si agisce sull'oggetto o su una copia).
Ma soprattutto ritengo decisamente pericoloso il fatto della GC non
deterministica, cioè che non si sa mai quando un oggetto viene distrutto.
Praticamente tu potresti continuare a lavorare con un oggetto senza sapere
che è un "dead men walking" e tutto d'un tratto la GC decide che questo deve
essere distrutto.
Risultato: cascata d'ecezioni. E tu vai a debuggare cosa, dove e quando è
successo.
Ciao

 la GC decide che questo deve essere distrutto.
Beh, se non ci sono errori nel codice questo non può accadere.
Non è che il GC si mette a distruggere oggetti a caso. Lo fa
solo quando questi *vanno* distrutti. Il problema della GC è che
gli oggetti vengono distrutti dopo (un dopo non quantificabile)
che il codice li ha resi candidati per la distruzione, non che
vengono distrutti prima.
Ciao e BUON 2003.


 essere distrutto.
Un oggetto può essere sottoposto a GC solo quando non ha nessun riferimento
attivo, il fatto che tu abbia da qualche parte un reference, fa si che
quell'oggetto non verrà mai eliminato dalla memoria.
Esiste in realtà una possibilità percui potresti avere un riferimento non
valido che è quello che si otterrebbe se tu settassi, nel metodo Finalize
della classe (se implementato) un nuovo riferimento all'oggetto che sta per
essere distrutto. La variabile in questo caso punterebbe ad un oggetto
inesistente. Fortunatamente il CLR è 'smart' è quindi, onde evitare questa
possibilità fa si che gli oggetti che implementano Finalize non vengano
distrutti immediatamente ma vengono prima messi in una finalization queue e
al successivo ciclo, se non vi sono reference attivi, eliminati
definitivamente dall'heap.
Questo è anche il motivo percui il metodo Finalize deve essere implementato
solo se effettivamente necessario.
HTH
-- 
Corrado Cavalli [Microsoft MVP]
UGIdotNET - 
http://www.ugidotnet.org

 Beh, se non ci sono errori nel codice questo non può accadere.
Ti faccio un esempio stupido (in VB6):
sub Button1_Click()
    MyObj = Nothing
End Sub
Sub Timer1_Timer()
    If Not MyObj Is Nothing Then
        MyObj.MyMethod
    End If
End Sub
Questo è potenzialmente pericoloso in 
VB.NET
, poichè dopo aver premuto
Button1 MyObj potrebbe rimanere non-nothing per molto tempo, nonostante in
realtà non sia un oggetto valido, e il codice è lineare e ben scritto.
Come si gestisce una cosa del genere in .NET?
Ciao

 realtà non sia un oggetto valido, e il codice è lineare e ben scritto.
scusa Zanna, non per dubitare della tua parola, ma sei sicuro che MyOby resti non-nothing?
intendo dire: le risorse utilizzate da MyObj si libereranno in futuro, ma una volta che
faccio myObj=nothing mi aspetto che la variabile MyObj, che mi sembra contenga un
puntatore, sia nothing immediatamente.
Salutoni
Sergio

 puntatore, sia nothing immediatamente.
E infatti e' cosi'... il puntatore e' immediatamente nullo, l'oggetto
puntato verra' distrutto in seguito dal GC
Gli eventuali "pericoli" casomai possono derivare da codice inserito nell'
equivalente del vecchio Class_Terminate (ora Finalize)
Immagina di avere una variable globale (shared) Flag di tipo boolean e una
classe fatta cosi':
Public Class Class1
    Protected Overrides Sub Finalize()
        MyBase.Finalize()
        Flag = False
    End Sub
End Class
ora prova a eseguire questo codice
Private Sub TestMe()
    Dim o As New Class1()
    Flag = True
    o = Nothing
End Sub
Sub Main()
    TestMe()
    'l'oggetto ora e' stato impostato a nothing
    'ed e' anche uscito di scope
    If Flag Then MsgBox("TRUE")
    'forza un ciclo di gabage collection
    'commentare l'istruzione per vedere la differenza
    GC.Collect()
    System.Threading.Thread.CurrentThread.Sleep(500)
    If Flag Then MsgBox("TRUE")
End Sub


[Luca Dormio] ha scritto:
(snippone)
ok, esempio compreso....
resta da dire che fare riferimento, dall'interno di una classe, ad una variabile condivisa
a livello di applicazione, è una cosa che grida vendetta la cospetto degli dei..... ;-)
Salutoni
Sergio

 ha scritto nel messaggio
news:av3lq4$bpnsh$1...@ID-173193.news.dfncis.de...

A parole si, ma nel mondo "reale" puo' succedere...
Nelle 539 classi che ho complessivamente nei sorgenti in ufficio i
Class_Terminate si contano sulle dita di due mani, pero' insomma, non
contiamoci delle balle; primo o poi in un programma puo' esserci bisogno di
*un* riferimento valido a livello di intera applicazione, puoi incapsularlo
in tutte le classi che vuoi ma alla fine della catena un qualche puntatore
da tenere aperto fino alla fine del programma ti scappa... basta tenere
conto del nuovo comportamento e agire di conseguenza.


 Come si gestisce una cosa del genere in .NET?
Il problema causato dalla GC non è che MyObj rimane non-nothing
(cosa che non avviene), ma che non c'è una garanzia di quando il
"distruttore" (finalize) verrà chiamato. Questo comporta che non
è possibile utilizzare l'idioma RAII nei linguaggi con GC,
ovvero *non* è possibile fare affidamento sul distruttore per
rilasciare le risorse acquisite dall'oggetto.
Una volta che si comprende questo (che può avere pesanti
ripercussioni sulla complessità del codice), non c'è alcun
pericolo...
Ciao.


 puntato verra' distrutto in seguito dal GC
Infatti ho detto una stupidaggine :)
A questo punto mi viene un dubbio: che differenza c'è tra obj.Dispose e obj
= Nothing?
Il solo fatto che la seconda libera immediatamente l'oggetto?
P.S.: ma è necessario usare il MyBase.Finalize() dopo tutti i discorsi sulla
GC?
Ciao

 GC?
Un paio di link su MSDN per entrambe le questioni
http://makeashorterlink.com/?A2EC62DF2
http://makeashorterlink.com/?J5FC22DF2
Molto brevemente:
Dispose e' un metodo che deve essere implementato, non e' necessariamente
esposto da tutte le classi... dovrebbe essere usato per rilasciare *le
risorse* usate dall'oggetto (non l'oggetto stesso) manualmente, invece che
aspettare il GC; tali risorse inoltre potrebbero essere "unmanaged" quindi
fuori dalla giurisdizione del framework e del GC, e a maggior ragione vanno
distrutte esplicitamente, nell'evento Finalize chiamato automaticamente dal
GC, o per l'appunto prima, da Dispose
