Newsgroup: it.comp.lang.delphi
Titolo: Che cosa comporta chiamare il Free di un oggetto gia' distrutto?

Salve,
ho un problema di questo tipo:
Applicazione Multithreaded.
2 liste gestiscono una serie di oggetti. Es. un ToDoList, ed una
DoneList.
Capita di dover assegnare alla lista Done alcuni elementi della lista
ToDO. Cosi' facendo mi trovo con 2 riferimenti allo stesso oggetto da
parte delle due liste.
Che cosa succede se chiamo 2 volte il free per gli oggetti presenti
nelle due liste? E' sconsigliabile? Porta a degli effetti indesiderati
non gestibili? Esiste un modo per sapere se un riferimento e' ancora
valido?
Grazie.
-- 
I'am what I'am, I do what I can

 valido?
invece che chiamare il Free, io utilizzerei la funzione FreeAndNil(), cosě 
che per sapere se un riferimento č ancora valido basta testare se
if Assigned()
ovvero
if riferimento <> nil
-- 
Mauro Falzari ( 
http://digilander.libero.it/mauro.falzari
 )
"Se guardi nell'abisso, anche l'abisso guarda in te." (Friedrich Nietzsche)

 if riferimento <> nil
Non e' cosi' semplice, se si utilizza FreeAnNil il riferimento viene
impostato a nil solo in una delle Liste, non in entrambe. Altrimenti
non c'erano problemi.
Esiste un modo per verificare se un puntatore ad un indirizzo di
memoria e' ancora valido come oggetto?


Puoi usare Assigned, a patto di liberare anche il puntatore suando
freeandnil.
Bye
A
--
Per rispondere non usare il reply ma scrivere al seguente indirizzo:
alsalvati(at)
supereva.it

 freeandnil.
Ok, ma se ho due liste con 2 elemento che puntano allo stesso oggetto e
facci FreeAnNil(Lista1.Items[x]) solo il riferimento Lista1.Items[x]
sara' impostato a nil mentre Lista2.Items[x] fara' riferimento alla
stessa allocazione di memoria che pero' a questo punta non sara' piu'
valida!


 non gestibili?
Ciao,
penso liberando due volte lo stesso oggetto dovresti avere una eccezione.
Potresti un po' strutturare gli oggetti, soprattutto l'Item, in modo tale da
avere un contatore... tipo le DLL di Windows.
Crei l'Oggetto.
Il costruttore dell'oggetto azzera la variabile contatore.
L'oggetto contenitore quando lo aggiunge alla sua lista incrementa la
variabile contatore. Cosě come qualsiasi altro oggetto contenitore che
aggiunge la stessa istanza dello oggetto item.
Subclassi il metodo Free dell'oggetto Item.
Il tuo metodo Free decrementa la variabile contatore... quando arriva a 0
richiami inherited. :-)
Oppure, per fare prima, non so perň se possa avere ripercussioni su altre
cose (credo di no), usi il classico Try ... Except quando liberi l'oggetto
item.
OPpure (sono sempre cose che non ho provato), liberi l'oggetto Item con
FreeAndNil, subclassi il metodo Free e gli fai controllare, prima di
liberare l'oggetto, il valore del puntatore Self: Se č a Nil esce e basta.
(Ma per questo ho dei dubbi... se Self č una var interna di tObject tira
fuori una eccezione)
Ciao
Giuseppe


E' ovviamente sconsigliabile e da evitare assolutamente. Gli effetti non
sono prevedibili e potrebbero cambiare da un compilatore all'altro. Se
proprio hai bisogno di piu' riferimenti, potresti implementare un contatore
di riferimenti e, invece di chiamare la Free, fare una tua FreeRef che
decrementa un contatore e chiama la Free solo quando questo contatore arriva
a zero. Oppure usare le interfacce implementando il reference counting
Ciao,
Stefano


Quando ho risposto, non avevo ancora letto la tua risposta :-)
Attenzione pero' all'uso del metodo Free nel modo che suggerisci xchè non e'
virtuale. Non funzionerebbe quindi se chiami il Free del TObject ma solo se
chiami quello della tua classe. Suggerivo appunto un nome di metodo
differente proprio x avere chiarezza in quel senso
Ciao,
Stefano

 virtuale...
Hai ragione. :-)
Ciao
Giuseppe

 interfacce implementando il reference counting
Penso che utilizzero' le interfacce, sono la soluzione piu' elegante
disponibile.


 memoria e' ancora valido come oggetto?
IMHO, ciò è impossibile.
Infatti il problema da te proposto si può semplificare in questo modo:
var
  o1, o2: TObject;
...
  o1:= TObject.Create;
  o2:= TObject.Create;
  o2:= o1;
  o1.Free;
a questo punto o2 contiene ancora un riferimento alla locazione puntata da 
o1 e anche ponendo
  o1:= nil
la situazione non cambia.
Giusto per pura curiosità ho voluto verificare la situazione con questo 
codice (serve una form con un componente Memo). Eseguendolo, vedrai che dopo 
l'assegnazione
   o2:= o1;
la o2 e o1 puntano alla stessa locazione di memoria.
//***********************************************************************
procedure TForm1.FormCreate(Sender: TObject);
  function _deref(o: TObject): Integer;
  asm
    MOV   EAX, o    	  //dereferenzia la locazione di memoria
  end;
var
  o1, o2: TObject;
const
  fs = '  >l''indirizzo di %s è $%x, che punta alla locazione $%x';
begin
  with Memo1, Lines do
  begin
    Clear;
    Align:= alClient;
    o1:= TObject.Create;
    Add('o1:= TObject.Create');
    Add(Format(fs, ['o1', Integer(@o1), _deref(o1)]));
    o2:= TObject.Create;
    Add('o2:= TObject.Create');
    Add(Format(fs, ['o2', Integer(@o2), _deref(o2)]));
    o2.Free;
    o2:= o1;
    Add('o2:= o1');
    Add(Format(fs, ['o2', Integer(@o2), _deref(o2)]));
    o1.Free;
  end
end;


 valida!
Ciao,
Sarò io cretino, ma non capisco dove sia il problema di assegnare un ID ad
ogni oggetto e mantenere due liste di ID.
Andrea

 Andrea
Il fatto e' che sono in tutto 3 liste, che vengono esposte da un
componente tramite alcuni eventi, per cui a seconda di che cosa fa
l'utente non ho la certezza che rimangano "integre".
Volevo trovare una soluzione general purpose, per il momento sto
utilizzando le interfacce come suggeritomi e mi sembra vadano alla
grande.
Saluti.
