IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Delphi Discussion :

[TList] : libération des éléments


Sujet :

Delphi

  1. #1
    Membre éclairé
    Inscrit en
    Novembre 2002
    Messages
    549
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 549
    Par défaut [TList] : libération des éléments
    Bonjour à tous,

    Je me demande quelle est selon la solution la plus propre pour libérer une TList

    1/on détruit l'objet TList et on libère la mémoire associée.
    2/on libére les éléments de la liste au préalable+ensuite on libére l'objet
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for PList:=0 to MyList.count-1 do
      begin
        PMyRecord:=MyList.Items[PList];
        Dispose(PMyRecord);
      end;
    MyList.free;
    Merci de vos lumières

    @

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 123
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 123
    Par défaut
    La Tlist n'est qu'un Tableau de Stockage
    La libération est à la charge du développeur

    si tu libère la liste, tu libère l'objet et son tableau, mais les pointeurs à l'intérieur ne seront pas libéré !
    Dans le cas d'objet, la TObjectList est très utile car elle libère les objets en fonction de l'option OwnsObjects.

    D'ailleurs pourquoi, la Tlist n'aurait pas une propriété OwnsPointers, tout simplement que dans le cas d'un objet, la liste demande à l'objet de se libérer, donc l'objet "sait" ce qu'il doit faire, dans le cas d'un pointeur, dispose ne connait que la longueur occupé par le pointeur et donc agit comme un FreeMem, il ne sait pas libéré les types pointeurs mais juste les types simples (integer, double, ...) et tableau fixe (shortstring, array[0..1] of integer)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for PList:=0 to MyList.count-1 do
        Dispose(PMyRecord(MyList.Items[PList]));
    MyList.free;
    MyList := nil;
    Ensuite, le passage par une variable temporaire de pointeur typé ou le cast, est très important pour que le Dispose effectue le Finaliez sur les chaines longues et les tableaux dynamiques, et si c'est un tableau dynamiques de chaines longues, il finalize chaque chaines, ... d'ailleurs si ta structure contient un pointer typé, il sera finalizé, mais si il contient un pointeur non type, il faut que tu fasse explitement de le dipose en castant le pointeur non typé

    voir ce sujet
    http://www.developpez.net/forums/sho...d.php?t=307572
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre éclairé
    Inscrit en
    Novembre 2002
    Messages
    549
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 549
    Par défaut
    Citation Envoyé par ShaiLeTroll
    La Tlist n'est qu'un Tableau de Stockage
    La libération est à la charge du développeur


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for PList:=0 to MyList.count-1 do
        Dispose(PMyRecord(MyList.Items[PList]));
    MyList.free;
    MyList := nil;
    Ensuite, le passage par une variable temporaire de pointeur typé ou le cast, est très important pour que le Dispose effectue le Finaliez sur les chaines longues et les tableaux dynamiques.
    Bonjour ShaiLeTroll,
    merci de ta réponse
    j'avais un doute sur ce coup là. Merci.

    Autre chose, est-il plus propre
    de faire
    1/
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    MyList.Free;
    MyList:=nil;
    2/

  4. #4
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 123
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 123
    Par défaut
    J'ai été habitué à Delphi 3 à 7, le FreeAndNil c'est récent ! à partir de 6 ? 7 ?
    En fait c'est pareil, le codé généré doit juste être plus long avec FreeAndNil, et je trouve que cette fonction ne fait plus trop objet, j'aime bien le .Free et le := nil (et puis j'en ai bcp dans mes vieux codes), sachant que le second n'est pas systématique, une variable locale n'a pas besoin d'être nullé, alors qu'un membre de classe, c'est recommandé ... je mets le := nil en connaissance de cause, par ce que je sais qu'il sera utile pas pour faire joli !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre éclairé
    Inscrit en
    Novembre 2002
    Messages
    549
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 549
    Par défaut

  6. #6
    Membre émérite Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Par défaut
    Citation Envoyé par ShaiLeTroll
    je trouve que cette fonction ne fait plus trop objet
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    procedure FreeAndNil(var Obj);
    var
      Temp: TObject;
    begin
      Temp := TObject(Obj);
      Pointer(Obj) := nil;
      Temp.Free;
    end;
    a mon avis, mieux vaut toujours preferer utiliser les fonctions de la librairie, framework

  7. #7
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 123
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 123
    Par défaut
    Oui, je connais cette fonction, pour l'avoir lu aussi

    et c'est "FrameWork" depuis D6, excuse moi d'avoir bossé en D3,4,5, elle n'apporte rien à part que le code est en une seule ligne, et remplace le manque de rigueur de certains pour la gestion des nulls et du Assigned ...
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    Membre émérite Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Par défaut
    Citation Envoyé par ShaiLeTroll
    elle n'apporte rien à part que le code ...
    c'est pas ce que j'a dit...

    j'ai seulement dit qu'il fallait plutot utiliser les fonctions fournie par la librairie Delphi ou un eventuel framework plkutot que chaque developpeur reinvente la roue a chaque fois...

  9. #9
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 123
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 123
    Par défaut
    Sinon, j'ai un modèle de code, et j'ai modifié "trycf" pour avoir
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    |variable := typename.Create();
    try
     
    finally
      variable.Free();
      variable := nil;
    end;
    et il m'arrive de supprimer "variable := nil;" parce qu'inutile dans le contexte, chacun ses habitudes moi, c'est CTRL+MAJ+T trycf, et pouf le code apparait ... je n'ai pas pris l'habitude du FreeAndNil, c'est tout, je préfère de loin un dev qui sait pourquoi il le fait que le faire juste pour dire que l'on fait sans savoir pourquoi !

    tu vois, je n'écrit jamais "obj <> nil" mais "Assigned(Obj)" c'est le même principe, les petites manies de chacun, et je pense que vu tes autres participations, Kafeine, tu as assez de recul et de connaissance informatique, que l'on ne se refait pas !

    et puis j'ai mon image de Troll à tenir, borné, chieur, cruel et intolérant pour la médiocrité
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  10. #10
    Membre éclairé
    Avatar de gb_68
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2006
    Messages
    232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2006
    Messages : 232
    Par défaut
    Bonjour,
    désolé de répondre à un sujet déjà marqué résolu, mais pour libérer les éléments d'un TList, il y a une solution simple.
    En fait il ne faut pas libérer les éléments qu'à la destruction de la liste, mais aussi lorsqu'un élément écrase un autre (exemple avec "Put" qui appelé par la propriété Items en écriture).
    Créer une classe descendante de TList et surcharger toutes les méthodes susceptibles de supprimer un élément serait difficile ... sauf que Borland (ou maintenant CodeGear) a très bien écrit cette liste .
    En effet, elle dispose d'une méthode Notify virtuelle qui est appelé à chaque fois qu'un évènement (qui peut être lnAdded lnExtracted lnDeleted) survient.

    Si la liste doit gérer en mémoire ses éléments, il suffit alors d'écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    TMyListe = class (TList)
      protected
        procedure Notify(Ptr: Pointer; Action: TListNotification); override;
      end;
    {...}
    procedure TMyListe.Notify(Ptr: Pointer; Action: TListNotification);
    begin
      case Action of
        lnAdded     : ;
        lnExtracted : ;
        lnDeleted   : dispose(PMyRecord(Ptr));
      end;
      inherited;
    end;
    Rem : c'est comme ça que TObjectList procède :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
    begin
      if OwnsObjects then
        if Action = lnDeleted then
          TObject(Ptr).Free;
      inherited Notify(Ptr, Action);
    end;
    Enfin pour Assigned et FreeAndNil :
    leur usage n'est pas obligatoire, mais est plutôt encouragé

    Assigned permet de tester avec une écriture unique pointeur, objet, réf de fonction/procédure, procedure/fonction d'objet, ...
    exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    typeTFunct = function : Pointer ;
    {...}
    var Obj :TObject ; Funct : TFunct;
    if (Obj = nil) or (Funct = nil) then//Funct = nil compare la valeur de retour de
    // Funct à nil (si Funct ne retournait pas de pointeur ou était une procedure 
    // => erreur à la compilation); pour savoir si Funct est assigné : @Funct = nil 
    // - et @@Funct ! pour l'adresse de la variable contenant le pointeur vers la
    // fonction !)
    {...}
    if Not Assigned(Obj) or Not Assigned(Funct) then // OK
    FreeAndNil assure lorsqu'elle est atteinte que l'objet sera à nil, même en cas d'exception lors du Free (les exceptions dans les destructeurs sont possibles en Delphi; exemple : TInterfacedObject qui peut lancer une exception EInvalidePointer dans BeforeDestruction)
    Donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    try
    {...}
    FreeAndNil(Obj); // si exception ici
    {...}
    finally
    Obj.Free; // pas de second appel au destructeur ici 
                // (car Free test Obj<>nil )
    end;

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. tranférer des éléments d'une base
    Par john_wayne dans le forum Décisions SGBD
    Réponses: 1
    Dernier message: 21/06/2004, 16h33
  2. [VB.NET] Enregistrement des éléments d'une listBox
    Par Hoegaarden dans le forum Windows Forms
    Réponses: 9
    Dernier message: 18/05/2004, 15h48
  3. couleurs des éléments 3D d'une appli
    Par Eugénie dans le forum MFC
    Réponses: 29
    Dernier message: 12/03/2004, 12h31
  4. [MFC] libération des objets GDI's
    Par Kevgeii dans le forum MFC
    Réponses: 5
    Dernier message: 01/02/2004, 11h37
  5. [TShellListView] Tri des éléments
    Par M.Dlb dans le forum Composants VCL
    Réponses: 4
    Dernier message: 16/12/2003, 23h35

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo