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 :

TDictionary : Utilisation de Free ou FreeAndNil


Sujet :

Delphi

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 37
    Points : 12
    Points
    12
    Par défaut TDictionary : Utilisation de Free ou FreeAndNil
    Bonjour à tous,

    Je planche depuis ce matin sur un problème avec Tdictionary et l'utilisation de ****.Free ou FreeAndNil(***)
    J'ai cru comprendre qu'après utilisation, il fallait vide la variable, mais actuellement cela ne me pose que des problèmes.
    A moins qu'il ne soit nécessaire d’exécuter cela a la fermeture de l'application ?

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    Var
    Messages : TMessage;
    FMsg : String;
     
    Begin
    FMsg := 'Paris';
    Messages := TMessage.Create; // ## Messages est actuellement vide ##
    DictionaryMessage.TryGetValue(FMsg, Messages); // ## Messages contient ce qu'il faut ##
      FreeAndNil(Messages); 
    ou // ## L'un ou l'autre ##
      Messages.Free; 
    // -----> A partir d'ici, DictionaryMessage (Paris) devient vide <--------

    Un exemple concret, qui pose problème a la seconde exécution:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
          else if cmd='RXQuestionEditGroupe' then
          begin
            //On extrait, et on set
            FMsg:= Copy(str, Pos('@', str)+1, Length(str)-Pos ('@', str)); //maman@groupeC
            idx:=pos('@',FMsg);
            FMsg2:=copy(FMsg,1,idx-1);   //maman
            FMsg3:= Copy(FMSG, Pos('@', FMSG)+1, Length(FMSG)-Pos ('@', FMSG)); //GroupeC
            form2.AddInfoDebugger('RECEPTION','Demande de Modif d''une question (Groupe) dans: '+FMsg2+' => '+FMsg3);
     
            Messages := TMessage.Create;
            if (DictionaryMessage.TryGetValue(FMsg2, Messages) = True) then
            begin
              Messages.Groupe := FMsg3;
              DictionaryMessage.AddOrSetValue(FMsg2, Messages);
            end
            else
            begin
              form2.AddInfoDebugger('ERREUR','Demande de modif de la question, elle n''existe pas: '+FMsg);
              tmycontext(acontext).Connection.IOHandler.WriteLn('Error@Demande de modif de la question, elle n''existe pas !');
            end;
            FreeAndNil(Messages);
          end
    Merci.

  2. #2
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 691
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 691
    Points : 13 121
    Points
    13 121
    Par défaut
    Tu détruis Message sans supprimer l'entrée dans le dictionnaire. Au second passage, Message est invalide.
    Tu n'as pas besoin de créer systématiquement Message mais uniquement s'il n'existe pas dans le dictionnaire. TryGetValue retourne l'instance de TMessage et non une copie.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if not DictionaryMessage.TryGetValue(FMsg2, Messages) then
      Messages := TMessage.Create;
     
    Messages.Groupe := FMsg3;
    DictionaryMessage.AddOrSetValue(FMsg2, Messages);
    Et pour le supprimer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if DictionaryMessage.TryGetValue(FMsg2, Messages) then
    begin
      Messages.Free;
      DictionaryMessage.Remove(FMsg2);
    end;
    Pour vider complètement le dictionnaire, il faut le récupérer sous forme de tableau pour énumérer les entrées. Quelque chose comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var
      MessagePair :TPair<string, TMessage>;
     
    begin
      for MessagePair in DictionaryMessage.ToArray do
      begin
        MessagePair.Value.Free;
        DictionaryMessage.Remove(MessagePair.Key);
      end;
    end;
    ou par Clear si l'événement OnValueNotify est renseigné (pour la destruction du TMessage).

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Bonjour,

    Effectivement, mon code est incomplet.
    Donc si je comprend bien, il ne s'agit pas d'une copie, donc si je le supprime, cela modifie aussi le dictionnaire ? (Les deux sont "liés")
    Je ne peux donc pas réutiliser Messages ? Puis-je libérer cette instance pour la réutiliser ?

    Mon but étant de faire plusieurs appels et modifications dans mon dictionnaire, en utilisant Messages.

  4. #4
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 691
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 691
    Points : 13 121
    Points
    13 121
    Par défaut
    Citation Envoyé par benda95280 Voir le message
    Donc si je comprend bien, il ne s'agit pas d'une copie, donc si je le supprime, cela modifie aussi le dictionnaire ? (Les deux sont "liés")
    Justement non, d'où la référence invalide au second passage.

    Citation Envoyé par benda95280 Voir le message
    Je ne peux donc pas réutiliser Messages ?
    Si, si, regarde mon premier bout de code. TMessage est créé s'il n'existe pas (au premier passage, TryGetValue échoue) puis réutilisé (TryGetValue retourne avec succès).

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Hummmmm...

    Donc je ne comprend toujours pas mon problème.
    Peut-être qu'une capture d'écran pourra montrer mon problème :

    Partie du code présenté dans les images:
    (Les arrêts sont sur les lignes 12 et 13)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        else if cmd='EditQuestion' then
          begin
           FMsg:= Copy(str, Pos('@', str)+1, Length(str)-Pos ('@', str));
           form2.AddInfoDebugger('INFO','Demande d''edit sur la question: '+FMsg);
           if DictionaryMessage.ContainsKey(FMsg) then
             begin
               Messages := TMessage.Create;
               DictionaryMessage.TryGetValue(FMsg, Messages);
               tmycontext(acontext).Connection.IOHandler.WriteLn('TXQuestionEditGroupe@'+Messages.Groupe);
               tmycontext(acontext).Connection.IOHandler.WriteLn('TXQuestionEditDesc@'+Messages.Desc);
               tmycontext(acontext).Connection.IOHandler.WriteLn('TXQuestionEditText@'+Messages.Text);
               freeandnil(Messages); // Messages.Free;
               DictionaryMessage.TryGetValue(FMsg, Messages);
             end
    PS: La ligne 13 me sert de point d’arrêt, et n'a aucun intérêt... je ne savais pas quoi mettre...

    Ligne 12:
    Nom : Delphi - ligne 12.png
Affichages : 526
Taille : 95,3 Ko

    Ligne 13:
    Nom : Delphi - ligne 13.png
Affichages : 490
Taille : 95,2 Ko

  6. #6
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 691
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 691
    Points : 13 121
    Points
    13 121
    Par défaut
    Pas à pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if DictionaryMessage.ContainsKey(FMsg) then
    Si vrai, un TMessage devrait déjà exister (à moins que tu aies fait plus tôt un AddOrSetValue(FMsg, nil)).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Messages := TMessage.Create;
    DictionaryMessage.TryGetValue(FMsg, Messages);
    Tu en crée cependant un mais qui ne sera jamais utilisé puisqu'au final tu récupères le message depuis le dictionnaire, tu écrases la référence.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    freeandnil(Messages); // Messages.Free;
    Tu penses détruire le message juste créé mais puisque tu as écrasé la référence, c'est celui contenu dans le dictionnaire qui est libéré. Celui juste créé subsistera jusqu'à la fermeture du programme (memory leak).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DictionaryMessage.TryGetValue(FMsg, Messages);
    Retourne vrai puisque l'entrée existe toujours. Seulement le pointeur Message est invalide puisque l'instance a été libérée (par erreur) précédemment. Violation d'accès à la prochaine utilisation de Message.

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Réponse plutot précise

    Donc, je n'ai pas besoin de créer a chaque fois mon Messages car je le récupère depuis le dictionnaire.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Messages := TMessage.Create;
    Je ne dois donc jamais libérer mon Messages ?

  8. #8
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 691
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 691
    Points : 13 121
    Points
    13 121
    Par défaut
    Citation Envoyé par benda95280 Voir le message
    Donc, je n'ai pas besoin de créer a chaque fois mon Messages car je le récupère depuis le dictionnaire.
    C'est ça.

    Citation Envoyé par benda95280 Voir le message
    Je ne dois donc jamais libérer mon Messages ?
    Uniquement lorsque tu supprimes l'entrée dans le dictionnaire, sinon jamais.

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Merci,

    Je peux donc utiliser Messages plus tard pour d'autres actions ? (Similaire) Avec le même appel ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DictionaryMessage.TryGetValue('AutreChose', Messages);

    Est-il possible d'écrire cela ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DictionaryMessage.Items['Toyota'].Groupe := 'test';
    Afin de définir directement une valeur dans le dictionnaire.

  10. #10
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 691
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 691
    Points : 13 121
    Points
    13 121
    Par défaut
    Citation Envoyé par benda95280 Voir le message
    Je peux donc utiliser Messages plus tard pour d'autres actions ? (Similaire) Avec le même appel ?
    Oui.

    Citation Envoyé par benda95280 Voir le message
    Est-il possible d'écrire cela ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DictionaryMessage.Items['Toyota'].Groupe := 'test';
    Oui parce que TMessage est un type objet. Ça ne serait pas possible s'il était de type record.

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Merci de ta réponse.
    Cela marche correctement maintenant

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

Discussions similaires

  1. Réponses: 12
    Dernier message: 22/12/2015, 14h15
  2. Utilisation de free
    Par Glork dans le forum Débuter
    Réponses: 3
    Dernier message: 07/02/2013, 12h16
  3. utilisation malloc free
    Par Débutant_ASM dans le forum Débuter
    Réponses: 5
    Dernier message: 17/03/2010, 10h11
  4. utilisation du free sur un char*
    Par kase74 dans le forum Débuter
    Réponses: 10
    Dernier message: 30/01/2009, 19h02
  5. [phpMyVisites] Utilisation chez Free
    Par .:H:. dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 5
    Dernier message: 11/03/2008, 18h53

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