como saber se um ponteiro não-nil tem uma referencia valida?
Boa tarde a todos:
Meu problema é o seguinte: fazer uma função que execute o método free em todos os objetos de um array de objetos.
a função isnil está abaixo:
ela me retorna true caso o objeto seja nil ou caso ele não esteja assigned.
o problema é que se eu coloco pra liberar 3 vezes o mesmo objeto, tipo assim :
ocorre access violation, pois isnil retorna true sempre. O que eu faço?
Meu problema é o seguinte: fazer uma função que execute o método free em todos os objetos de um array de objetos.
procedure LimpaTudo(vObjetos: array of TObject); var i: Integer; o: TObject; begin try for i := Low(vObjetos) to High(vObjetos) do begin if not isNil(vObjetos[i]) then begin o := TObject(vObjetos[i]); MessageBox(0, PChar(string(o.ClassName)), ´limpando´, 0); Pointer(vObjetos[i]) := nil; o.Free; Pointer(o) := nil; end; end; except end; end;
a função isnil está abaixo:
function isNil(pObjeto: tobject): boolean; begin if (pobjeto = nil) then MessageBox(0, ´objeto = nil´, ´teste´, 0) else MessageBox(0, ´objeto <> nil´, ´teste´, 0); if (not assigned(pobjeto)) then MessageBox(0, ´objeto not assigned´, ´teste´, 0) else MessageBox(0, ´objeto assigned´, ´teste´, 0);; isNil := ((pobjeto = nil) or (not assigned(pobjeto))); end;
ela me retorna true caso o objeto seja nil ou caso ele não esteja assigned.
o problema é que se eu coloco pra liberar 3 vezes o mesmo objeto, tipo assim :
LimpaTudo([Edit1, Edit1, Edit1]);
ocorre access violation, pois isnil retorna true sempre. O que eu faço?
Vitor Rubio
Curtidas 0
Respostas
Massuda
05/10/2006
Você não precisa testar se é nil antes de dar Free. Free é (acho) o único método que tem tratamento para o caso do objeto ser nil. Assim, este código executa sem problemas...Por outro lado, testar se um objeto é válido é bem mais complicado. Dê uma olhada neste artigo [url=http://hallvards.blogspot.com/2004/06/hack-6checking-for-valid-object.html]Checking for a valid object instance[/url] (em inglês); note que o código sugerido pode falhar dependendo da versão do Delphi.
var O: TObject; ... O := nil O.Free; ...
GOSTEI 0
Siam
05/10/2006
Acho que o problema é que vc está atribuindo nil após o Free para uma variável local e não para o seu array original de objetos.
GOSTEI 0
Siam
05/10/2006
Uma forma mais simples sem precisar testar seria:Com isso o parâmetro [b:75e6dfa84a]var[/b:75e6dfa84a] fará com que seu array de origem seja atualizado para nil e o FreeAndNil fará o teste antes.
procedure LimpaTudo(var vObjetos: array of TObject); var i:Integer; begin for i := 0 to High(vObjetos) do FreeAndNil(vObjetos[i]); end;
GOSTEI 0
Vitor Rubio
05/10/2006
Você não precisa testar se é nil antes de dar Free.
Mas se eu der um free num objeto invalido, dá access violation. Testa meu código pra você ver.
Acho que o problema é que vc está atribuindo nil após o Free para uma variável local e não para o seu array original de objetos.
Talvez seja isso, mas eu queria passar um array na hora. Se eu tivesse que passar um array por referência, teria que declarar um array primeiro e preenche-lo, e depois passa-lo.
Então no meu caso
[quote]procedure LimpaTudo(var vObjetos: array of TObject); var i:Integer; begin for i := 0 to High(vObjetos) do FreeAndNil(vObjetos[i]); end;
não daria certo, porque eu não tenho o array, estou criando na hora, como se fosse um array constante.
Existe algum outro jeito de se passar parametros infinitos para uma função?
como eu crio uma function igual a writeln do pascal antigo, que aceita um número variado-indefinido de parametros?
quero construir uma função que de free em varios objetos de uma vez sem usar listas.
GOSTEI 0
Massuda
05/10/2006
[quote:a5fa989b2d=´vitor^_^´]Mas se eu der um free num objeto invalido, dá access violation. Testa meu código pra você ver.[/quote:a5fa989b2d]Um valor ser nil é diferente de ser inválido.
O valor nil equivale numericamente ao zero. É fácil de testar. Free testa se o objeto é nil antes de chamar Destroy.
Um valor diferente de nil (numericamente não zero) pode ou não ser um objeto válido. O artigo que indiquei mostra como testar se um valor não-nil é ou não um objeto válido.
O valor nil equivale numericamente ao zero. É fácil de testar. Free testa se o objeto é nil antes de chamar Destroy.
Um valor diferente de nil (numericamente não zero) pode ou não ser um objeto válido. O artigo que indiquei mostra como testar se um valor não-nil é ou não um objeto válido.
GOSTEI 0
Siam
05/10/2006
Não sei como estão sendo criados e destruídos esses objetos, mas outra alternativa seria utilizar um TList para mandar liberá-los.
GOSTEI 0
Vitor Rubio
05/10/2006
Um valor ser nil é diferente de ser inválido.
O valor nil equivale numericamente ao zero. É fácil de testar. Free testa se o objeto é nil antes de chamar Destroy.
Então, isso eu sabia. Mas como você deve ter visto no meu código, o problema é quando eu tenho duas variaveis diferentes, ou posições diferentes de um array de objetos, apontando para o mesmo objeto. Se eu der um free, ele vai liberar o objeto. Setando nil, ele vai setar só essa variavel pra nil, mas a ´copia´ dela não. A copia vai ficar com um ponteiro inválido, onde eu não posso dar free, e o assigned retorna true.
Precisaria de uma forma de liberar varios objetos de uma vez, com uma unica função.
Um valor diferente de nil (numericamente não zero) pode ou não ser um objeto válido. O artigo que indiquei mostra como testar se um valor não-nil é ou não um objeto válido.
Não entendi o artigo, ele disponibiliza uma biblioteca que só funciona em delphi 3 e que precisa de outras bibliotecas. A função principal dessa biblioteca usa uma outra que não está disponível.
GOSTEI 0
Massuda
05/10/2006
[quote:d418bd128d=´vitor^_^´]Não entendi o artigo, ele disponibiliza uma biblioteca que só funciona em delphi 3 e que precisa de outras bibliotecas. A função principal dessa biblioteca usa uma outra que não está disponível.[/quote:d418bd128d]No final do artigo, ele dá outra função, mais simples, ValidateObj(), que não tem relação com o código que ele apresenta no início do artigo. Me parece (não testei) que ela deve resolver seu problema.
GOSTEI 0
Vitor Rubio
05/10/2006
A função é esta:
ela não funciona nesse caso:
que é o caso da minha procedure para limpar um array de objetos, não pode ter objetos repetidos. Alem disso, essa função é meio mistica: não entendi o porque de declarar PPVmt = ^PVmt; se não usa e tambem o porque que o ´Other : array[0..17] of pointer;´ é um array de 18 ponteiros....
de qualquer forma, valew!
function ValidateObj(Obj: TObject): Pointer; type PPVmt = ^PVmt; PVmt = ^TVmt; TVmt = record SelfPtr : TClass; Other : array[0..17] of pointer; end; var Vmt: PVmt; begin Result := Obj; if Assigned(Result) then try Vmt := PVmt(Obj.ClassType); Dec(Vmt); if Obj.ClassType <> Vmt.SelfPtr then Result := nil; except Result := nil; end; end;
ela não funciona nesse caso:
procedure TForm1.Button1Click(Sender: TObject); var o: TEdit; begin o := Edit1; edit1.Free; ValidateObj(o); o.Free; end;
que é o caso da minha procedure para limpar um array de objetos, não pode ter objetos repetidos. Alem disso, essa função é meio mistica: não entendi o porque de declarar PPVmt = ^PVmt; se não usa e tambem o porque que o ´Other : array[0..17] of pointer;´ é um array de 18 ponteiros....
de qualquer forma, valew!
GOSTEI 0
Siam
05/10/2006
E se vc mantivesse um TList de objetos liberados e na hora de liberar, checaria se ele já foi adicionado na lista.
GOSTEI 0
Massuda
05/10/2006
Porque você não tenta usar algo mais simples...Eu não gosto desse código, mas deve funcionar no seu caso.
Duas perguntas:
* porque o array contem elementos duplicados?
* poderia dar uma idéia de como isso é usado?
procedure LimpaTudo(vObjetos: array of TObject); var i: Integer; begin for i := Low(vObjetos) to High(vObjetos) do begin try vObjetos[i].Free; except // ignora problemas ao destruir end; end; end;
Duas perguntas:
* porque o array contem elementos duplicados?
* poderia dar uma idéia de como isso é usado?
GOSTEI 0
Vitor Rubio
05/10/2006
E se vc mantivesse um TList de objetos liberados e na hora de liberar, checaria se ele já foi adicionado na lista.
É uma ótima solução mas eu não queria usar Tlist nesse caso.
Porque você não tenta usar algo mais simples...Código:
procedure LimpaTudo(vObjetos: array of TObject);
var
i: Integer;
begin
for i := Low(vObjetos) to High(vObjetos) do begin
try
vObjetos[i].Free;
except
// ignora problemas ao destruir
end;
end;
end;
Eu não gosto desse código, mas deve funcionar no seu caso.
isso funcionaria mais ou menos, mas ele ficaria parando nos exceptions, durante o debug, atrapalhando. As vezes vc pode ate confundir cm um erro de verdade.
Duas perguntas:
* porque o array contem elementos duplicados?
* poderia dar uma idéia de como isso é usado?
Na verdade, um objeto repetido foi passado por engano, mesmo assim, não deveria dar essa exception ao liberar um objeto que já foi liberado. Se analisar a fundo, a minha procedure é mesmo inutil :oops: , mas quando deu esse erro surgiu essa curiosidade. O que eu queria era, ao inves de fazer:
objeto1.free; objeto2.free; objeto3.free; ... ... ... objeton.free;
fazer:
Limpatudo(objeto1, objeto2, objeto3....);
eu nem vou usar mais essa procedure. Valew pela ajuda!
GOSTEI 0