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 :

Question simple Free / Variable


Sujet :

Delphi

  1. #1
    Membre éclairé Avatar de peter27x
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 029
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 029
    Points : 757
    Points
    757
    Par défaut Question simple Free / Variable
    Hello,
    j'ai trouvé ceci dans un programme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    PROCEDURE TToto.FreeObject( Item : TObject );
    Begin
      Item.Free;
      Item := Nil; // Cela ne sert à rien de mettre à NIL car "Item" n'est pas un paramètre par variable
    End;
    Vous aurez remarqué le commentaire sur le ":= Nil".

    Ma question en suivant : d'accord, mais alors dans ce cas là, le free sert il à quelque chose ?

    Je suppose qu'il ne fait que libérer l'espace mémoire alloué localement à Item, mais pas l'espace mémoire de la variable manipulée par l'appelant de la procédure... Mais j'attends les avis des experts.

    Merci.

  2. #2
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 301
    Points
    11 301
    Billets dans le blog
    6
    Par défaut
    Les objets sont passés par adresse [EDIT=mea culpa]=> c'est équivalent à un var Item: TObject;

    mais il existe depuis Delphi 5 au moins une procedure FreeAndNil qui fait déjà ça et (je crois) ne lève pas d'exception si l'argument n'est pas assigné.

    [EDIT] l'intérêt de mettre Nil, c'est de ne pas faire planter si on cherche à utiliser cet Item déjà libéré à condition de tester si bien assigné : if Assigned(Item) then Item.Execute;
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Citation Envoyé par peter27x Voir le message
    Ma question en suivant : d'accord, mais alors dans ce cas là, le free sert il à quelque chose ?
    Bien sûr puisque le paramètre pointe bien sur un objet existant

    Citation Envoyé par tourlourou Voir le message
    Les objets sont passés par adresse => c'est équivalent à un var Item: TObject;
    Pas tout à fait ! Item (sans var ni const) est une copie du pointeur locale à la fonction. Affecter nil à Item n'affectera donc que sa copie.

    Citation Envoyé par tourlourou Voir le message
    mais il existe depuis Delphi 5 au moins une procedure FreeAndNil qui fait déjà ça et (je crois) ne lève pas d'exception si l'argument n'est pas assigné.
    Free commence par faire un test sur Self <> nil avant d'appeler Destroy pour s'assurer de l'assignation du pointeur. C'est pour cela qu'il est conseillé d'appeler Free plutôt que Destroy directement. FreeAndNil cumule simplement l'appel à Free et l'assignation de nil au pointeur (passé en var ici)

  4. #4
    Membre éclairé Avatar de peter27x
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 029
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 029
    Points : 757
    Points
    757
    Par défaut
    OK merci à vous.
    Donc avec var, ce n'est pas une copie du pointeur mais le pointeur lui même qui est passé, et le nil aurait alors son intérêt. Sans var c'est une copie, mais comme elle pointe sur la même adresse mémoire que l'original, le free va aller libérer cette adresse là, donc on est bon.
    Pour le freeandnil en effet c'est un programme assez ancien, ça devait pas exister à l'époque de son écriture.
    Désolé, mais après plus de deux ans sans pratiquer, j'ai un peu perdu certaines bases.

  5. #5
    Membre éclairé Avatar de peter27x
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 029
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 029
    Points : 757
    Points
    757
    Par défaut
    Quand même une remarque : en C, par exemple, un paramètre passé par adresse ou bien par valeur, c'est pas exactement comme en Delphi, c'est ça ? Le passage de paramètre Delphi est un peu particulier, non ?

  6. #6
    Membre éclairé Avatar de peter27x
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 029
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 029
    Points : 757
    Points
    757
    Par défaut
    J'ai trouvé ceci dans un tuto Delphi du site (celui de Didier Mailliet) :

    C. Paramètre donnée variable

    1. définition

    Il s’agit d’un passage de paramètres par valeur. On ne précède le nom du paramètre d’aucun mot (ni var, ni const ni out).
    Le paramètre peut avoir une valeur avant l’appel, sa valeur peut être modifiée dans la procédure, la modification n’est pas
    transmise au retour.

    2. exemple


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    procedure essai (x,y : byte);
    begin
    y := x // y prend la valeur de x
    end;
    Var
    a,b : byte:
    ...
    a:= 3; b:= 2;
    essai (a,b); // a et b conservent leurs valeurs
    Ma question : si l'affectation d'une valeur à y ne s'applique pas à b, alors pourquoi, si j'ai bien compris les explications de Andnotor, le fait de faire y.free s'appliquerait à b ?

    Merci.

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    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 : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    ne confond pas un type simple comme Byte et un objet !

    Si l'on repart sur ta méthode FreeObject

    FreeObject appelle la méthode Free, cela invoque du code DE l'objet, il manipule directement SA mémoire
    C'est le Free qui travaille sur l'objet !

    FreeObject effectue une affectation d'une nouvelle valeur mais tout le code est DANS FreeObject et cela ne modifie pas l'objet mais la référence local Item sur celui-ci !

    Pense à Self, sur Free ou toute méthode d'objet, il y a un paramètre invisible qui est l'objet lui-même, si l'on traduisait Free objet en un Free procédural :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure TObject.Free;
    begin
      if Self <> nil then
        Destroy;
    end;
    deviendrait

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure Free(Obj: TObject);
    begin
      if Obj <> nil then
        Destroy(Obj);
    end;
    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
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 693
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    y.free ne s'applique pas à b, mais à la donnée pointée par b. Nuance

    Modifie ton essai ainsi pour t'en convaincre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure Essai(x, y :PByte);
    begin
      y^ := x^; //La valeur pointée est modifiée
      y  := x;  //Le pointeur ne l'est pas
    end;
     
    essai(@a ,@b);
    En sortie, b vaudra a.

  9. #9
    Membre éclairé Avatar de peter27x
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 029
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 029
    Points : 757
    Points
    757
    Par défaut
    Je pense que je me suis mal fait comprendre.

    Pour faire simple voici ce code simplifié :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    PROCEDURE FreeObject( Item : TObject );
    Begin
      Item.Free;
    end;
     
    var
      b : TObject;
     
    begin
      FreeObject(b);
      // est il équivalent à
      b.Free;
      // ?
    end;
    Ce que je cherche à savoir, c'est si depuis l'appelant, la variable b ici de type TObject passée par valeur (sémantiquement c'est ça) est affectée par le Free exécuté dans la procédure ou pas.

    Car pour moi, si item est une copie de b (ce qui me semble logique) alors le item.free doit s'appliquer à item (la variable locale à la procédure), mais pas à la variable b de l'appelant.

    Désolé si je vous embête avec tout ça...

    Si ça vous embête pas alors coooool

  10. #10
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    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 : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Voir le sujet Pointeur sur objet

    Citation Envoyé par peter27x Voir le message
    Je pense que je me suis mal fait comprendre.
    On a pourtant répondu à cette question, un objet est toujours passé par référence, une sorte de pointeur, cela ne copie pas un objet dans un autre, cela ne fait qu'affecter ce pointeur à un autre variable
    Pour copier un objet, il existe la méthode Assign, il n'y a pas de mécanisme de copie d'objet comme en C++

    le var ou le const en modifications de fonctionns s'applique à la référence sur l'objet (son pointeur) mais pas sur l'instance de l'objet (son contenu)

    Tu n'as jamais pensé au Sender d'un TNotifyEvent, cela impliquerait que cela copie les objets lors d'un Evènement puis l'objet est passé en paramètre du gestionnaire, imagine une TTreeView rempli, si cela faisait une copie, cela recopierait donc les TTreeNode[s] ?
    Cela serait tellement pas pratique et contre-performant !


    Extrait de l'aide
    Une variable de type classe est en fait un pointeur qui référence un objet. Plusieurs variables peuvent donc désigner le même objet. Comme les autres pointeurs, les variables de type classe peuvent contenir la valeur nil.
    Chaque classe (et par conséquent chaque composant) est en fait un pointeur. Le compilateur déréférence automatiquement les pointeurs de classe à votre place, aussi n'avez-vous généralement pas besoin de vous poser ces questions. Le statut des classes en tant que pointeurs devient important lorsque vous passez une classe comme paramètre. En général, vous transmettrez les classes par valeur plutôt que par référence. Car les classes sont déjà des pointeurs, c'est-à-dire des références ; transmettre une classe par référence serait transmettre une référence à une référence.
    Sinon le code de FreeAndNil c'est justement un Free encapsulé, cela fonctionne très bien, le mot clé var n'est là QUE pour l'affectation
    Note que c'est même plutôt un NilAndFree, qui est plus prudent en multi-thread, on "oublie" la référence avant de libérer, ainsi un Assigned se glissant entre les deux étapes protégera correctement l'accès à l'objet (utile lors de la libération d'une TThreadList ou d'un TCriticalSection, si l'on essaye de l'utiliser pour effectuer un lock alors que l'on est en train de la libérer, l'inverse n'étant pas problématique car le Destroy lock l'objet avant de le libérer)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure FreeAndNil(var Obj);
    var
      Temp: TObject;
    begin
      Temp := TObject(Obj);
      Pointer(Obj) := nil;
      Temp.Free;
    end;
    que l'on comprend mieux en C++Builder

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    void __fastcall FreeAndNil(void *Obj);
    appel
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    TObject *Obj = new ... // En C++Builder, le * est obligatoire pour les TObject, on comprend mieux l'aspect pointeur\référence implicite du Delphi
    FreeAndNil(&Obj);
    Donc on passe en fait un TObject**, on comprend mieux le terme "une référence à une référence.", le Delphi simplifie cette notion de pointeur et cette simplification provoque ta confusion
    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

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Oui, le résultat est le même.
    Ce que tu n'as pas encore compris est qu'avant l'appel, il y a déjà deux zones mémoire distincts : le pointeur sur l'objet et l'instance d'objet proprement dite. A l'appel de la procédure, seul le pointeur est copié localement.

    Même sans penser à l'appel d'une procédure, prenons l'exemple suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var
      a :TObject;
      b :TObject;
     
    begin
      a := TObject.Create;
      b := a;
      b.Free;
      b := nil;
    end;
    Nous avons bien créé un objet et fait pointé "a" sur sa zone mémoire (le résultat de Create). Nous copions ensuite ce pointeur uniquement dans "b", il n'y a pas de copie de l'objet complet !
    Enfin le seul et unique objet est détruit par l'intermédiaire du pointeur "b". "a" n'est pas effacé mais pointe maintenant dans les choux ! (violation d'accès)

  12. #12
    Membre éclairé Avatar de peter27x
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 029
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 029
    Points : 757
    Points
    757
    Par défaut
    OK, merci à vous, maintenant c'est plus clair en effet.

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

Discussions similaires

  1. question simple sur une variable date
    Par xavier_dcf dans le forum Débuter
    Réponses: 2
    Dernier message: 14/02/2013, 15h53
  2. Question simple sur les variables
    Par roxydu33 dans le forum Débuter
    Réponses: 3
    Dernier message: 14/04/2010, 21h00
  3. Question simple : Double dollar d'une variable PHP
    Par foxbond dans le forum Langage
    Réponses: 7
    Dernier message: 04/10/2009, 22h24
  4. Simple question sur les variables
    Par terry90 dans le forum Langage
    Réponses: 6
    Dernier message: 26/06/2009, 15h59
  5. Variable sans propriétés - question simple
    Par tavarlindar dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 28/05/2008, 18h48

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