Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 12 sur 12
  1. #1
    Membre chevronné Avatar de peter27x
    Inscrit en
    janvier 2007
    Messages
    1 024
    Détails du profil
    Informations forums :
    Inscription : janvier 2007
    Messages : 1 024
    Points : 603
    Points
    603

    Par défaut Question simple Free / Variable

    Hello,
    j'ai trouvé ceci dans un programme :

    Code :
    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 Yves Lemaire
    Biologiste ; Progr(amateur)
    Inscrit en
    mars 2005
    Messages
    2 178
    Détails du profil
    Informations personnelles :
    Nom : Homme Yves Lemaire
    Âge : 51
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : mars 2005
    Messages : 2 178
    Points : 4 296
    Points
    4 296

    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 et Code Typhon 4.41 sous Win 7 64 bits - Code Typhon 4.50 sous Ubuntu 12.04 64 bits (VM)

  3. #3
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    septembre 2008
    Messages
    3 379
    Détails du profil
    Informations forums :
    Inscription : septembre 2008
    Messages : 3 379
    Points : 5 466
    Points
    5 466

    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 chevronné Avatar de peter27x
    Inscrit en
    janvier 2007
    Messages
    1 024
    Détails du profil
    Informations forums :
    Inscription : janvier 2007
    Messages : 1 024
    Points : 603
    Points
    603

    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 chevronné Avatar de peter27x
    Inscrit en
    janvier 2007
    Messages
    1 024
    Détails du profil
    Informations forums :
    Inscription : janvier 2007
    Messages : 1 024
    Points : 603
    Points
    603

    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 chevronné Avatar de peter27x
    Inscrit en
    janvier 2007
    Messages
    1 024
    Détails du profil
    Informations forums :
    Inscription : janvier 2007
    Messages : 1 024
    Points : 603
    Points
    603

    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 :
    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 Confirmé Sénior Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    juillet 2006
    Messages
    10 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : juillet 2006
    Messages : 10 037
    Points : 12 856
    Points
    12 856

    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 :
    1
    2
    3
    4
    5
    procedure TObject.Free;
    begin
      if Self <> nil then
        Destroy;
    end;
    deviendrait

    Code :
    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

    Halte à la ségrégation des Cinémas, VO sur Paris, VF en Banlieue, Abonnement résilié !

  8. #8
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    septembre 2008
    Messages
    3 379
    Détails du profil
    Informations forums :
    Inscription : septembre 2008
    Messages : 3 379
    Points : 5 466
    Points
    5 466

    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 :
    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 chevronné Avatar de peter27x
    Inscrit en
    janvier 2007
    Messages
    1 024
    Détails du profil
    Informations forums :
    Inscription : janvier 2007
    Messages : 1 024
    Points : 603
    Points
    603

    Par défaut

    Je pense que je me suis mal fait comprendre.

    Pour faire simple voici ce code simplifié :

    Code :
    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 Confirmé Sénior Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    juillet 2006
    Messages
    10 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : juillet 2006
    Messages : 10 037
    Points : 12 856
    Points
    12 856

    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 :
    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++ :
    void __fastcall FreeAndNil(void *Obj);
    appel
    Code c++ :
    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

    Halte à la ségrégation des Cinémas, VO sur Paris, VF en Banlieue, Abonnement résilié !

  11. #11
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    septembre 2008
    Messages
    3 379
    Détails du profil
    Informations forums :
    Inscription : septembre 2008
    Messages : 3 379
    Points : 5 466
    Points
    5 466

    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 :
    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 chevronné Avatar de peter27x
    Inscrit en
    janvier 2007
    Messages
    1 024
    Détails du profil
    Informations forums :
    Inscription : janvier 2007
    Messages : 1 024
    Points : 603
    Points
    603

    Par défaut

    OK, merci à vous, maintenant c'est plus clair en effet.

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

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •