Newsgroup: it.comp.lang.delphi
Titolo: Come far porre automaticamente a Nil il riferimento a una  form (il suo puntatore) quando questa viene chiusa

Il concetto e' semplice:
- All'atto della creazione devo salvare l'indirizzo del puntatore della form 
in una variabile (proprieta') della form stessa.
- All'atto del Destroy uso questo indirizzo per porre il valore puntato a 
Nil
eseguito il destroy a causa della chiusura della form per esempio da 
pulsante close trovero' la Form=Nil
La form deve essere creata a Run-Time:
Form2:=TForm2.Create(Self);
// Salvo l'indirizzo del puntatore dell'oggetto form nella variabile Tag che 
e' una Integer, quindi compatibile con puntatore
Form2.Tag:=Integer(@Form2);
...
// Alla pressione del pulsante Close
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree; // Al Close dealloco l'oggetto, verra' eseguito il destroy
end;
procedure TForm2.FormDestroy(Sender: TObject);
var P: PInteger;
begin
P:=PInteger(Self.Tag); // Contiene l'indirizzo della Form2 (del suo 
puntatore)
P^:=Integer(Nil);        // pongo il puntatore contenuto a tale indirizzo a 
Nil
end;
In qualunque momento da codice posso cosi' sapere se la form2 e' allocata o 
no con
if Form2=Nil then
    // non e' allocata, se mi serve la creo
Ovviamente la cosa si puo' generalizzare per altri oggetti, salvo aggiungere 
una variabile analoga al .Tag se questa non esiste.
Giorgio

una variabile analoga al .Tag se questa non esiste.
Giorgio, come ti è già stato fatto presente, questa tecnica è errata,
basata peraltro su un principio oggettivamente errato ed io eviterei
di consigliarla.
Se ho una form "autodistruggente", sono legittimato a scrivere:
F := TForm2.Create(nil);
F.Tag := Integer(@F);
F.Show;
F := TForm2.Create(nil);
F.Tag := Integer(@F);
F.Show;
Peccato che alla distruzione della prima form, venga in realtà messo a
nil il puntatore alla seconda, creando un colossale memory leak.  Non
voglio immaginare, a quel punto, i fuochi d'artificio che verranno
fuori chiudendo la seconda form.
 

 una variabile analoga al .Tag se questa non esiste.
Infatti pensavo che questo comportamento può benissimo essere implementato
ad un derivato del tcustomform e quindi diventare disponibile sempre per le
tue esigenze.
Ciao!!!
-- 
Morde. 
ICLDweb: 
http://www2.samatel.com/icld/

 fuori chiudendo la seconda form.
Hai svolto qualche test sui leak? Questa tecnica la adotto da 4 anni e 
l'eseguibile che la usa a gogo e' stato testato piu' volte per i leak: non 
c'e' traccia di questi e non ha mai manifestato problemi alla chiusura.
Per quanto riguarda i "fuochi d'artificio" ti ricordo che se la form2 
risulta distrutta col suo puntatore a Nil un suo free dalla form1 si 
comporta perfettamente: rammenta che il free procede nel destroy solo se 
l'oggetto ha il puntatore <>Nil, altrimenti non fa nulla (help del metodo 
FREE) e questo avvalora la mia tesi.
Non capisco perche' continui a contraddire una cosa daltronde ovvia.
Il Delphi allo start setta i puntatori degli oggetti a Nil, se lo faccio io 
quando non sono allocati e' sconsigliato! Non solo ma da una certa versione 
ha inserito la funzione FreeAndNil, evidentemente ci sara' un motivo.
Giorgio

quando non sono allocati e' sconsigliato!
Stai attento a non fare deduzioni sbagliate da ciò che scrivo.
Io sconsiglio di utilizzare i "round-trip" come quello che suggerivi
sopra, perché si rivelano enormemente pericolosi.
Ti ricordo comunque da dove siamo partiti: tu dicevi che ti meravigli
del fatto che Delphi non preveda il reset a nil di un puntatore, una
volta che la memoria puntata viene deallocata.  Io ti ho detto che
Delphi fa benissimo a non farlo, perché questa operazione è inutile
nel 99% dei casi e nel restante 1% si tratta sicuramente di uno
sbaglio progettuale.  Ma d'altronde, non voglio convincerti per forza,
rimani pure delle tue idee.  Chiudo qui.

 Il concetto e' semplice [...]
Può essere una soluzione, purché si faccia attenzione ai contesti in cui 
può essere utilizzata già evidenziati nel resto di questa discussione.
Personalmente, io preferisco adottare un metodo differente, forse più 
complesso (all'inizio) e laborioso, ma che ritengo più sicuro: 
introdurre nella classe che si occupa di generare i form secondari (che 
potrebbe essere la stessa MainForm) un metodo che deve essere richiamato 
da parte di tali Form per segnalare la propria distruzione, inserendo 
poi nell'implementazione di questo metodo tutte le istruzioni necessarie 
per aggiornare il "luogo" in cui ho memorizzato un riferimento al form 
secondario, ammesso che io abbia effettivamente bisogno di farlo.
Questa soluzione prescinde dal tipo di contenitore usato per il 
riferimento al form secondario creato: può trovarsi in una lista, in un 
campo privato o in qualsiasi altra locazione che verrà aggiornata quando 
il metodo apposito che serve ai form secondari per segnalare la propria 
distruzione viene richiamato.
Se più oggetti devono essere informati della distruzione del form, è 
sufficiente costruire un meccanismo di notifica; peraltro, è possibile 
prendere spunto di una simile architettura direttamente dalla libreria 
VCL e dal suo meccanismo di "Free Notification".
Nel tuo esempio di codice non hai comunque gestito il caso in cui 
all'interno della proprietà /Tag/ non venga memorizzato alcun 
riferimento (in sostanza, che non sia necessario richiedere 
l'impostazione di un ipotetica variabile contenente il riferimento a 
*nil*) se lo sviluppatore non lo desidera.
Supponendo di voler generalizzare il tuo procedimento per qualsiasi 
applicazione, l'uso della proprietà /Tag/ secondo me è piuttosto 
pericoloso perchè potrebbe essere sovrascritto oppure la tua routine 
potrebbe sostituirne il valore quando viene creato il form secondario e 
magari lo sviluppatore intendeva farne un uso differente, ad esempio 
memorizzare un indice o qualche altro dato in forma libera.
Concludendo, non ritengo che il tuo procedimento sia sbagliato nel modo 
più assoluto, ma solo che si applica ad una cerchia molto ristretta di 
casi, benchè possa essere suggeribile per chi, magari agli inizi, voglia 
usufruire di una rapida soluzione al problema, però con il rischio che, 
con il complicarsi del codice nel progetto, si rientri in uno dei casi 
denunciati che portano ad effetti collaterali e indesiderati. :-/
Ciò che spero è che tu non consideri una pazzia il fatto che Delphi non 
gestisca questa problematica in modo automatico (quindi, senza 
possibilità di intervento) e soprattutto usando questo metodo. ;-)
Ciao,
   Marco.
-- 
MARCO BREVEGLIERI
  (
http://www.marco.breveglieri.name
)

 rimani pure delle tue idee.  Chiudo qui.
Penso anch'io sia inutile proseguire, ciao Giorgio

l'oggetto e' ancora allocato, col conseguente grave errore.
Stai creando un falso problema.  Se il programmatore necessita di
sapere una cosa del genere, vuol dire che ha perso il controllo della
sua applicazione da moltissimo tempo.  Nei fatti, se il codice
prevede, a un certo punto, la deallocazione di un oggetto, non
dovrebbe esserci una condizione successiva in cui mi chiedo se
quell'oggetto è ancora allocato o meno.  Quello che tu richiedi a
Delphi è una cosa insensata, non necessaria e a volte impossibile da
fare.

 di intervento) e soprattutto usando questo metodo. ;-)
Non ho parlato di pazzia e cmq in modo automatico non significa 
necessariamente senza possibilita' d'intervento.
Ciao Giorgio 

saperlo, pena un errore grave.
Sto ancora aspettando un esempio (te l'avevo già chiesto) di tale
contesto.

 saperlo, pena un errore grave.
Lo definisci "problema" ma non è un problema; se è un problema 
realmente, lo è tanto quanto considerare "problema" il fatto che 
scrivendo in una variabile perdo il valore precedentemente contenuto al 
suo interno... non è un problema, è un principio di funzionamento, nulla 
di più.
Il dato di fatto è che una variabile diversa da *nil* non garantisce che 
l'oggetto corrispondente sia allocato: non è un problema, è un principio 
da tenere in considerazione poichè, per tutti i motivi già 
precedentemente elencati, non è possibile (e sarebbe causa di grossi 
problemi) che Delphi imposti a *nil* un riferimento dopo la chiamata al 
metodo /Free/. Su questo spero che si sia raggiunto una posizione di 
accordo.
Basta dire questo, poi chiunque può regolarsi di conseguenza per 
impostare autonomamente il riferimento incriminato a *nil*.
Se si debbono fare controlli e verificare se un oggetto è istanziato 
oppure no controllando che il contenitore scelto per il riferimento sia 
diverso da *nil*, usa la proprietà Tag, usa un'altra proprietà apposita 
del tuo form personalizzato, passa il puntatore a un metodo, usa un 
meccanismo di notifica...ciascuno è libero di imbastire il meccanismo 
che crede più semplice, redditizio, funzionale, meno problematico e via 
discorrendo.
Al massimo, si può discutere di quale sia il metodo più efficace e 
sicuro per risolvere un determinato problema.
Io comunque, almeno in questo frangente, continuo a preferire il mio - 
che poi è quello della VCL (e forse "standardizzato", concedimi il 
termine, da un Design Pattern, ma sono ancora in fase di apprendimento a 
riguardo) rispetto allo "scambio di puntatori con cast forzati"...sarò 
un incorreggibile megalomane, che posso dirti? ;-) :-D


termine, da un Design Pattern[...]
Il pattern 'Observer' è effettivamente uno standard per quelle
applicazioni in cui diverse entità hanno bisogno di ricevere notifiche
da altre entità e riduce al minimo l'accoppiamento tra esse.  E' il
caso della FreeNotification di cui parlavi e, in generale, dell'intero
sistema basato sugli eventi.

 questo spero che si sia raggiunto una posizione di accordo.
Se Delphi mettesse a nil i puntatori deglio oggetti rilasciati forse 
basterebbe un "remark" del tipo:
attenzione che viene posto a Nil lo stesso puntatore che e' stato usato 
all'atto della creazione, cioe se
Oggetto:=TOggetto.Create(..);
a Nil si ritrovera' Oggetto e non altri puntatori il cui valore e' stato 
copiato da Oggetto.
Con una semplice modifica al TList si potrebbe togliere anche il problema 
che avete evidenziato.
L'help di Delphi, le API sono ricche di remark e questi non fanno certo 
perdere di significato l'argomento che si sta trattando.
Il problema c'e' come ho gia' riferito con gli oggetti che si 
"autodistruggono", negli altri casi e' il programmatore che lo evita.
Ci ritroviano con un Assigned che non serve, abbiamo un Free che controlla, 
prima di procedere al rilascio, se il puntatore e' diverso da Nil, controllo 
che in questo caso a nulla serve dal momento che delphi non mette a nil nel 
caso dell'autodistruzione.
Faccio presente, anche per rispondere ad una affermazione di Andrea, che il 
programmatore non puo' sapere quando l'utilizzatore chiude una form 
autodistruggente e questo non significa affatto "perdere il controllo del 
programma".
Una incongruenza bella e buona c'e' a meno di non voler tapparsi occhi e 
orecchie e far finta di nulla.
E' chiaro anche che si puo' programmare in modo che il problema non si 
presenti mai, basta non riutilizzare componenti autodistruggenti, ma questa 
e' una forzatura dal momento che costringe a tenere allocate fino alla 
chiusura delle risorse che  in alcuni casi ho necessita' di riutilizzare 
solo saltuariamente.
Tornando al codice che ho proposto nella prima email alla fine dopo che 
vostre affermazioni hanno riferito di leak, di pericolosi round-tip, l'unico 
dato di fatto certo e' che non e' ne' pericoloso ed e' del tutto esente da 
leak!
Questo e' il mio modo di vedere, senza ragionare con dogmi e senza ritenere 
che tutto cio proposto da Borland sia "oro colato".
Ciao Giorgio 

 che tutto cio proposto da Borland sia "oro colato".
Grazie per la considerazione che dai al mio pensiero.
Un minimo di rispetto verso chi impiega parte del proprio tempo cercando 
di proporre soluzioni e sostenere una discussione tecnica evitando di 
relegare le opinioni altrui a ragionamenti legati a dogmi che accettano 
tutto quando proposto da Borland come "oro colato" (che poi è tutto da 
dimostrare) sarebbe il minimo in un contesto civile.


 leak!
Non è vero, se vuoi convincerti di questo fa pure.
Proponi a qualunque esperto del linguaggio la tua tecnica e riceverai
pernacchie ;-)
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 
Salve,
   scusate se mi intrometto ma l'argomento mi sembra interessante.
Io ho sempre utilizzato questo approccio:
1) quando ho bisogno di richiamare Form:
if Form <> nil then
   Form := TForm.Create(Self)  // lo creo se non già acreato.
else Form.WindowState := Normal;  // richiamo se già creato, poiché è 
certamente minimizzato.
2) quando l'utente chiude il form:
  2.1) nell'evento OnCloseQuery imposto CanClose := True;
  2.2) nell'evento OnDestroy imposto Form := nil;
Questo, ho verificato, comporta, almeno (se non altri che non ho ancora 
riscontrato), il problema che in un'applicazione MDI non posso avere 
aperti il form padre insieme al form figlio perché nel momento che 
dovessi chiudere prima il form padre cominciano i fuochi d'artificio, 
nel senso di AV a più non posso.
Non sono riuscito, date le mie conoscenze a risolvere il problema.
Posso chiedere come risolvere il problema in questi casi?
Le specifiche sono:
1) applicazione MDI;
2) se il form è aperto riportalo in primo piano (quando il form è in 
secondo piano è minimizzato) altrimenti crealo e visualizzalo.
3) Ogni form deve essere creato solo al momento del bisogno.
Grazie.
Ciao, Luigi.

[...]in un'applicazione MDI non posso avere [...]
Il modello MDI è "deprecated" persino da parte di Microsoft, lo si è
detto spesso.  Abbandonalo.

dimostrare) sarebbe il minimo in un contesto civile.
D'altonde io non credo che siano in molti a prendere per oro colato
ciò che dice Borland, visti i numerosi bug della VCL.  Si tratta,
semplicemente, di adottare le tecniche migliori di programmazione,
cosa che è del tutto svincolata da un linguaggio specifico.  Lo stesso
ragionamento che stiamo facendo per classi e puntatori a istanze in
Delphi, lo si può fare per il C++ o per qualsiasi altro linguaggio
basato su un modello a oggetti analogo.

 il valore?
Certo a questo non avevo pensato,  al destroy il puntatore potrebbe non 
esistere piu' mettendo in seria difficolta' delphi. Beh come avevo detto non 
ho dogmi: la frase era solo riferita a me non a altri, non c'e'ra nessuna 
intenzione scorretta.
Spero di non avervi fatto perdere troppi chili..
Ciao, Giorgio

 Spero di non avervi fatto perdere troppi chili..
Mah... buttarne giù qualcuno non mi fa di certo male. :-)


detto spesso.  Abbandonalo.
Per quali motivi č sconsigliabile usare il modello MDI?
Non penso che l'MDI comporti particolari problemi se usato correttamente,
anzi ha il vantaggio di permettere l'apertura di piů form dello stesso
tipo, molto utile se si vogliono, per esempio, fare analisi di dati con
criteri differenti per poi confrontarle tra loro.
Saluti.
Alessandro
--- posted by geoForum on 
http://www.delphiedintorni.it

Per quali motivi è sconsigliabile usare il modello MDI?
Ci sono vecchi articoli di Microsoft (del '94/'95) in cui se ne parla.
E' un modello ufficialmente "deprecato" da parte di Microsoft, che non
lo utilizza neanche più nelle sue applicazioni, in parte perché
promuove uno schema "application-centric" anziché "document-centric"
come, ad esempio, il moderno Office.


Quali sono gli svantaggi dell'MDI?
