Guillemouze
Messages postés991Date d'inscriptionsamedi 25 octobre 2003StatutMembreDernière intervention29 août 2013
-
25 sept. 2007 à 18:29
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 2022
-
26 sept. 2007 à 18:40
salut a tous, j'ai un petit probleme, et je me demande si ce comportement est normal.
En gros, delphi me reaffecte toujours la meme adresse memoire; ce qui me pose probleme car je fais une comparaison de pointeur qui me dit que le pointeur est le meme alors que l'objet a ete recréé.
Voici grosso modo ma structure
2 classes : TCmd et TOwner, TCmd contient un pointeur vers un TOwner.
une instance cmd: TCmd pointant vers une instance owner:TOwner.
une liste:TObjectList contenue dans owner
Les appels sont les suivants :
cmd := owner.liste.last;
cmd.back;
-> cmd.Terminer;
->owner.Terminer(cmd);
->liste.Remove(cmd); //liste.ownsobjects = true
liste.Add(TCmd.create); // l'objet cree a la meme adresse que "cmd" !!!
<-
<-
<-
cmd2 := owner.liste.last;if cmd2 cmd then onRecommenceLeTraitement; // cmd2 cmd alors qu'il a bien ete detruit
Pensez vous que ce comportement est normal? En effet, je recréé un objet d'un type juste apres la liberation d'un objet du meme type.
Si c'est normal, avez-vous une solution? Creer un objet bidon entre temps pour decaler la memoire?
cs_Loda
Messages postés814Date d'inscriptionvendredi 3 novembre 2000StatutMembreDernière intervention30 juillet 20093 26 sept. 2007 à 13:12
re,
le but de cela
"if cmd2 = cmd then onRecommenceLeTraitement;" est bien de savoir si il s'agit du même object? j'ai juste?
donc un ID devrait faire le truc. non?
mais, de manière général. Une instance qui a été libérée devrait toujours être affectée à NIL. Sauf si tu es sur que tu n'y fait plus référence plus tard. Et tu es exactement dans le cas contraire: tu sais que tu y fait référence plus tard.
la méthode de comparaison d'adresse pour des objects est bien et très utile, lorsque tu compare des objects qui n'ont pas été libéré. sinon, ça vaut rien: c'est pas fiable et dangereux (AV).
bref, si ton code est conséquent, j'ajouterais un ID. Le plus simple et fiable.
genre:
implementation:
var
lastID :integer = 0;
contructor TBaseMaClass.Create();
begin
fID := lastID;
inc(lastID);
....
end;
bon code,
Loda
<hr size="2" width="100%" />Se poser les bonnes questions est le premier pas pour trouver les bonnes réponses.
Guillemouze
Messages postés991Date d'inscriptionsamedi 25 octobre 2003StatutMembreDernière intervention29 août 20136 26 sept. 2007 à 12:35
c'est vrai que c'est pas terrible de tester une ref d'objet qui a ete detruit.
mais en fait, le traitement effectué derriere tout ca est un peu plus compliqué .
Par exemple, cmd.back ne fait appel a cmd.Terminer que dans un certain cas, sinon un autre traitement est effectué qui ne provoque pas la destruction de cmd. Le liste.Remove ... liste.Add n'est pas non plus benin, je traite de classes heritees de TCmd, et je ne fais pas toujours le add.
Les appels que j'ai decrit sont le process qui me pose probleme, mais c'est loin d'etre le seul chemin, et je n'ai decris que les actions importantes pour comprendre le probleme.
je pense que le probleme vient surtout de la conception de ma structure generale
Au passage, quelque chose qui peut parraitre choquant est le fait que la fonction TCmd.Terminer par exemple contient une partie executée sur une instance detruite !!!
procedure TCmd.Terminer;
begin
...
Owner.Terminer(Self);
... //ce code est executé alors que self est detruit ! (il n'y a en fait aucun code ici)
end;
PS: j'ai fait un petit test :
var
s1, s2: TStringList;
begin
s1 := TStringList.Create;
s1.Free;
s2 := TStringList.Create;
ShowMessage(BoolToStr(s1 = s2, true)); //ca affiche bien "true"
end;
Guillemouze
Messages postés991Date d'inscriptionsamedi 25 octobre 2003StatutMembreDernière intervention29 août 20136 26 sept. 2007 à 13:26
lol, c'est exactement ce que j'ai fait en attendant de trouver une autre solution, si elle existe
tu as bien compris le but de la manoeuvre.
tu dis : "Une instance qui a été libérée devrait toujours être affectée à NIL". c'est bien gentil, mais affecter nil a une variable ne veut pas dire que toutes les references vers cet objet seront nil. en l'occurence, mon objet se trouve dans une TObjectList (la reference de base). ma cmd n'est qu'une variable temporaire, dans une procedure quelconque, pointant vers celui ci. Je ne peux donc pas, au moment de la liberation de mon objet (=sa suppression de la TObjectList), mettre cette varable a nil, qui est totalement inconnue du possesseur de l'objet !!!
ceci dit, ta phrase reste vrai tout de meme, on ne free pas une variable "globale" sans la niler
Vous n’avez pas trouvé la réponse que vous recherchez ?
cs_Loda
Messages postés814Date d'inscriptionvendredi 3 novembre 2000StatutMembreDernière intervention30 juillet 20093 26 sept. 2007 à 14:07
"C'est bien gentil, mais affecter nil a une variable ne veut pas dire que toutes les references vers cet objet seront nil."
C'est vrai ! et C'est là que les AV arrivent. Les réf sur des object qui risque d'être détruit à tout moment: à éviter.
Note qu'une gestion par ID permet d'éviter quelques peu ce type de problème. Si tu garde l'ID et non la réf de l'objet, lorsque tu vas récupere l'object depuis un autre endroit, tu verra que l'ID ne point plus sur rien. Mais c'est plus lent !
Note aussi, que tu peux garder une list des instance crées (dans TOUT ton programme) dans l'unit de la class.
var
MaListPriveeGlobal : TListObject; //own = false
contructor TBaseMaClass.Create();
begin
...
MaListPriveeGlobal.add(self);
...
et dans le destroy tu l'enlève.
ceci te permet d'ajout une méthode global (ou dit de class) qui te retourne une instance en fct de son ID.
bon code!
Loda
PS:
" ta phrase reste vrai" , c'est pas de moi. C'est une habitude de prog. ;-)
Le point important est que le test if assigned(ref) then ref.Do ne marche QUE si tu assign NIL a ta ref après l'avoir detruite!
et que le test assigned est le seul moyen d'empecher des AV (a part un try except vide. si on peu appelé ça empêcher)
ceci devient important si tu as des constructeur et destructeur un peu complexe ou avec des options
<hr size ="2" width="100%" />Se poser les bonnes questions est le premier pas pour trouver les bonnes réponses.
vus qu'une addresse se libere (celle de A) avant la creation de C, C reprend l'addresse libre (donc celle de A)
si on recrée A a la fin (quand B,C,D sont libre), A reprendra l'addresse memoire qu'il avait au tout debut puisque libre.
Mais attention, ce fonctionnement est propre a Windows, il n'est pas certains que Linux, Unix ou MacOS gere les pointeurs de la même façon.