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

Langage Delphi Discussion :

Court circuiter le ref-count d'un TInterfacedObject!


Sujet :

Langage Delphi

  1. #21
    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
    Euh, pourquoi j'utilise une interface, c'est parce que c'est ton sujet qui parlait des interfaces...
    Dans le cadre d'une inter-opérabilité entre mon programme et celui de partenaire, je leur fourni un objet avec une spécification donnée et une utilisation précise ... je ne vois pas le rapport entre le fait d'utiliser une interface et le fait de bien utiliser cette dernière ???

    L'interface n'a pas pour but de gérer la libération !
    Elle a pour but de faire d'un ensemble de programmes hétéroclytes un tout dans un système ...
    D'ailleurs, lorsque l'on fait des bibliothèques de type, on peut ajouter dans la TLB des objets d'implémentation (descendant de TOleServer vers une CoClasse), qui lorsque l'on fait l'import via Delphi ou via Visual, génère des classes qui vont encaspsuler l'interface, et du coup, cela s'utilise comme n'importe quel objet, instanciation et libération ...


    Il y a ce qu'on appele une documentation, et si le guss ne le la lit pas, eh bien ça fuira, ... ceux qui seront consciencieux appeleront Delete ... eh, je ne suis pas un troll pour rien ! Je suis exigeant avec moi-même, j'en attends autant des autres ...

    On dirait qu'il est loin temps où l'on faisait un GetMem, il était tellement logique de faire à un moment donné un FreeMem, ...

    Après biensur tout dépend d'où vient l'arbre, si le client à créer l'arbre, il a donc fait des Add ... donc si il y a des Add, il y a du Delete ou du Clear ...
    mais si l'arbre vient d'une résultat d'une fonction genre GetArbre, eh bien, il y aura une fonction ReleaseArbre, ... qui libérera l'arbre, ... et si il garde un noeud de côté, et bien il devrait penser à faire aussi son nettoyage ... je sais pas mais c'est logique, on peut pas toujours macher le travail, parfois, j'ai l'impression que l'on prend nos utilisateurs de nos objets pour des crétins ... pour moi, les grands classiques Open\Close, Create\Free, et tous les binomes du même genre ...

    En fait, je pense que c'est aussi une histoire de style de programmation ...
    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

  2. #22
    Membre actif Avatar de Suryavarman
    Homme Profil pro
    Développeur 3D
    Inscrit en
    Mai 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur 3D
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Mai 2006
    Messages : 233
    Points : 245
    Points
    245
    Par défaut
    bein pour moi si je créer un arbre et que je le place dans un ITree c'est que j'ai décidé de reléguer la responsabilité de la gestion mémoire, de sa manipulation, etc... à un interface. Une fois refiler à une interface on n'y touche plus. L'objet sera manipuler par différentes interfaces qui n'auront pas la notion de Delete que possède dans ton cas ITree.
    Exemple :
    Mon ITree est un élément observable, dans mon code je décide de libérer tous les observables. Bein dans ce cas, je suis cuit car celui ou celle qui aura implémentée l'objet aura eu la flemme de faire une libération correct. SI tu fais de l'interface tu le fais BIEN.

    Et osef si microsoft, code-gear ou truc muche à fait comme-ci ou comme ça. La référence c'est l'esprit du langage et non les compromis de temps, d'argent etc...des autres.
    "Quand le monde est dangereux, l'humilité est un facteur de longévité." ( Baxter "Evolution" )

  3. #23
    Membre éclairé 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
    Points : 736
    Points
    736
    Par défaut
    j'ai pas tout compris quand a la finalité du truc mais le titre suggere de court circuite le ref counting.

    a mon sens il suffit pour cela de renvoyer une valeur bidon dans _AddRef et _Release

    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
    23
    24
    25
    26
    27
    28
    29
     
      TInterfacedObjectSansRC = class(TObject, IInterface)
      protected
        function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
        function _AddRef: Integer; stdcall;
        function _Release: Integer; stdcall;
      end;
     
     
    { TInterfacedObjectSansRC }
     
    function TInterfacedObjectSansRC._AddRef: Integer;
    begin
      Result := -1;
    end;
     
    function TInterfacedObjectSansRC._Release: Integer;
    begin
      REsult := -1;
    end;
     
    function TInterfacedObjectSansRC.QueryInterface(const IID: TGUID;
      out Obj): HResult;
    begin
      if GetInterface(IID, Obj) then
        Result := S_OK
      else
        Result := E_NOINTERFACE;
    end;
    Akim Merabet

  4. #24
    Membre actif Avatar de Suryavarman
    Homme Profil pro
    Développeur 3D
    Inscrit en
    Mai 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur 3D
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Mai 2006
    Messages : 233
    Points : 245
    Points
    245
    Par défaut
    Oui mais là l'objet qui en dérivera sera impropre à la réutilisation. Et quand il sera mis sous forme d'interface, tu ne pourras plus distinguer une interface qui a été crée avec un TInterfacedObject, d'une qui a été crée avec TInterfacedObjectSansRC.
    "Quand le monde est dangereux, l'humilité est un facteur de longévité." ( Baxter "Evolution" )

  5. #25
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    Citation Envoyé par Kaféine Voir le message
    a mon sens il suffit pour cela de renvoyer une valeur bidon dans _AddRef et _Release
    C'est un peu ce que j'allais dire. Il y a deux approches possibles :
    - Celle de Kaféine qui consiste à neutraliser définitivement le refcount dans l'implémentation de _AddRef et _Release. Cependant cette approche désactive le refcount dans tous les cas.
    - Je pense que ce que Suryavarman veut, c'est garder le refcount pour détruire automatiquement le Parent lorsqu'il n'est plus utilisé. Par contre, il veut que les enfants puissent avoir une référence sur le Parent, sans que cette dernière ne soit comptabilisée comme une référence du Parent pour le refcount et ainsi ne pas bloquer la destruction du parent à cause des références que possèdent les enfants. Ouf...

    Donc pour définir ce genre de référence faible, il y a une solution toute simple, qui prend une et une seule ligne de code : Appeler explicitement _Release :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      Client.Parent := Parent; // On vient de référencé Parent. Son compteur de référence a été incrémentée. On a une référence forte.
      Client.Parent._Release; // Décrémente le compteur de ref de Parent. La référence existe donc toujours, par contre elle n'est plus prise en compte par le compteur. La référence devient une référence faible.

  6. #26
    Membre actif Avatar de Suryavarman
    Homme Profil pro
    Développeur 3D
    Inscrit en
    Mai 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur 3D
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Mai 2006
    Messages : 233
    Points : 245
    Points
    245
    Par défaut
    non. C'est l'interface que tu manipules pas l'objet. Sinon t'es obligé de créer une interface qui renvoi _Addref et _Release;

    de plus y a pas marqué sur la variable je suis une référence faible, et même si c'était dans les specs ou le nom de la variable, je suis sur qu'en réfléchissant un peu d'en d'autres situations ou voir celle-ci avec l'arbre il n'y aura pas que AddRef à faire et surement pas en un seul endroit du code.
    "Quand le monde est dangereux, l'humilité est un facteur de longévité." ( Baxter "Evolution" )

  7. #27
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    oui enfin y'avais une autre approche tout aussi simple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    procedure TChild.setParent(AParent:IParent);
    begin
     fParent:=AParent;
     fParent._Release;
    end;


    edit: ah mince c'était donné 2 posts au dessus
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  8. #28
    Membre éclairé 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
    Points : 736
    Points
    736
    Par défaut
    Citation Envoyé par Suryavarman
    Oui mais là l'objet qui en dérivera sera impropre à la réutilisation. Et quand il sera mis sous forme d'interface, tu ne pourras plus distinguer une interface qui a été crée avec un TInterfacedObject, d'une qui a été crée avec TInterfacedObjectSansRC.

    pour savoir qu'elle objet implemente l'interface j'ai une solution simple:
    tu declare un interface (encore ) qui renvoit l'objet qui implemente l'interface. genre avec mon exemple precedent.

    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
     
    IMonInterface = interface
    [GUID]
     function implementeur: TObject;
    end;
     
     
    TInterfacedObjectSansRC = class(TObject, IInterface, IMonInterface)
      protected
        function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
        function _AddRef: Integer; stdcall;
        function _Release: Integer; stdcall;
        function implementeur: TObject;
      end;
     
     
    { TInterfacedObjectSansRC }
     
    function TInterfacedObjectSansRC.implementeur: TObject;
    begin
      Result := Self;
    end;
     
    function TInterfacedObjectSansRC._AddRef: Integer;
    begin
      Result := -1;
    end;
     
    function TInterfacedObjectSansRC._Release: Integer;
    begin
      REsult := -1;
    end;
     
    function TInterfacedObjectSansRC.QueryInterface(const IID: TGUID;
      out Obj): HResult;
    begin
      if GetInterface(IID, Obj) then
        Result := S_OK
      else
        Result := E_NOINTERFACE;
    end;
    tu coup tu peux tester la classe de l'objet qui implemente l'interface

    Simple is beautiful
    Akim Merabet

  9. #29
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    C'est l'interface que tu manipules pas l'objet. Sinon t'es obligé de créer une interface qui renvoi _Addref et _Release;
    Désolé mais là je ne te suis pas. Pour qu'il y ait comptage de référence, ça veut dire que tu travailles avec une interface qui dérive de IUnknown, donc qui possède AddRef et Release. Si ton interface dérive de rien du tout, tu n'as pas de comptage de référence.

    Le comptage de référence sur les interfaces ce n'est pas magique ! Lorsque tu crée une référence sur une interface, Delphi appele implicitement AddRef. Lorsque tu réaffectes ta variable à nil pour supprimer la référence (ou lorsque la variable qui référence l'interface est finalisée) Delphi appele implicitement Release.

    de plus y a pas marqué sur la variable je suis une référence faible, et même si c'était dans les specs ou le nom de la variable, je suis sur qu'en réfléchissant un peu d'en d'autres situations ou voir celle-ci avec l'arbre il n'y aura pas que AddRef à faire et surement pas à un seul endroit du code.
    Ouais, à ce que je vois, l'informatique c'est toujours l'art de résoudre des problèmes que tu n'aurais pas si tu t'en passais.

  10. #30
    Membre actif Avatar de Suryavarman
    Homme Profil pro
    Développeur 3D
    Inscrit en
    Mai 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur 3D
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Mai 2006
    Messages : 233
    Points : 245
    Points
    245
    Par défaut
    [edit]oups j'avais pas vu les msg suivants
    ?!!!???
    fParent c'est quoi ?

    Si c'est un pointeur sur un TNodes ... ça veut dire que tu fige le parent à être à la base un TNodes...tu sors du principes des interfaces.

    Si c'est un IParent faut que IParent est la méthode de _Release mais...(voir mon msg précédent ).

    La seul solution propre ( apparemment ) :
    Soit tu utilises ma structure (si ta le delphi qui convient)
    soit ta pas envie ou ta pas le delphi qui faut et tu met une property dans INodes qui affect et renvoi un INodes (pour le parent ) mais dans TNodes cette property sera stocker dans un POINTER ou un record InterfaceFaible.
    de plus y a pas marqué sur la variable je suis une référence faible, et même si c'était dans les specs ou le nom de la variable, je suis sur qu'en réfléchissant un peu d'en d'autres situations ou voir celle-ci avec l'arbre il n'y aura pas que AddRef à faire et surement pas à un seul endroit du code.
    Ouais, à ce que je vois, l'informatique c'est toujours l'art de résoudre des problèmes que tu n'aurais pas si tu t'en passais.
    C'est pas faux, mais là j'avais la flemme de retrouver les autres cas qui ont été rencontrés , je sais juste que c'est pas une solution d'incrémenter et de décrémenter le refcount ça amène à des cas difficiles à résoudre.

    [EDIT]


    Citation:
    C'est l'interface que tu manipules pas l'objet. Sinon t'es obligé de créer une interface qui renvoi _Addref et _Release;
    Désolé mais là je ne te suis pas. Pour qu'il y ait comptage de référence, ça veut dire que tu travailles avec une interface qui dérive de IUnknown, donc qui possède AddRef et Release. Si ton interface dérive de rien du tout, tu n'as pas de comptage de référence.

    Le comptage de référence sur les interfaces ce n'est pas magique ! Lorsque tu crée une référence sur une interface, Delphi appele implicitement AddRef. Lorsque tu réaffectes ta variable à nil pour supprimer la référence (ou lorsque la variable qui référence l'interface est finalisée) Delphi appele implicitement Release.
    Tu me met dans le doute, je regarderais demain. Car quand j'ai voulu le faire j'ai du créer une interface supplémentaire je n'avais pas accès à AddReg et Release... merdouille :p tu marque un point on dirait je vérifie demain.

    [EDIT] Oui j'ai confondu avec le fait que j'avais du deboguer, et donc de mettre FRefCount dans l'interface. Désolé

    Mais ça change rien que bidouiller le Addref et le Release c'est casse gueule enfin si c'est dans une petite structure où ça sera très local oui je suis d'accord . Mais bon créer un pointer sur l'interface ( ex : aIntf : Pointer) c'est moins risqué.
    [EDIT]
    Moins risqué je sais pas en fait un pointer c'est non typé , et le AddRef Release peut vite devenir compliqué.
    "Quand le monde est dangereux, l'humilité est un facteur de longévité." ( Baxter "Evolution" )

  11. #31
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    La solution donnée initialement, avec des record avancés, est sympathique. Il n'en demeure pas moins que la bonne solution est en effet d'appeler _Release après l'affectation, mais aussi _AddRef avant que cette variable ne soit modifiée (ou remise à nil, ce qui inclut la libération de son objet porteur).

    Je donnerais donc quelque chose comme ceci :
    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    type
      TTreeNode = class(TInterfacedObject, ITreeNode)
      private
        FParent: ITreeNode;
      protected
        procedure SetParent(Value: ITreeNode);
      public
        constructor Create(AParent: ITreeNode);
     
        procedure CleanupInstance; override;
      end;
     
    constructor TTreeNode.Create(AParent: ITreeNode);
    begin
      inherited Create;
     
      SetParent(AParent);
    end;
     
    procedure TTreeNode.SetParent(Value: ITreeNode);
    begin
      if FParent <> nil then
        FParent._AddRef;
      FParent := Value;
      if FParent <> nil then
        FParent._Release;
    end;
     
    procedure TTreeNode.CleanupInstance;
    begin
      SetParent(nil);
      inherited;
    end;
    Pourquoi utiliser CleanupInstance plutôt que le destructeur ? En gros, c'est parce que le _Release automatique de la libération de l'objet a lieu dans TObject.CleanupInstance. Donc il est naturel d'anticiper cette remise à nil avec notre méthode SetParent dans une redéfinition de CleanupInstance.
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  12. #32
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    oui enfin y'avais une autre approche tout aussi simple
    j'utilise a peu près le même code dans une de mes classes afin d'avoir une référence faible, avec cependant 2 nuances :
    il faut voir TBaseItems comme une TCollection et TBaseItem comme un TCollectionItem, (une version "Interfaces" de la collection de delphi)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    procedure TBaseItem.SetBaseItems(const Value: IBaseItems);
    begin
      FBaseItems := Value;
      // l'ajout d'un item ne doit pas incrementer le compteur de référence
      //  if value <> nil then IInterface(FBaseItems)._Release; // non compatible D5
      if value <> nil then IUnknown(FBaseItems)._Release;
    end;
    les variations c'est que je vérifie si la valeur est pas nil avant de faire un release.
    mais aussi bien sur que je suis obligé de caster mon IBaseItems en IUnknow
    (au début j'utilisais IInterface, mais ne fc pas sous D5) pour pouvoir utiliser _release

    EDIT : je précise que je suis obligé de caster car mon FBaseItems est une ref d'interface vers IBaseItems et non pas IUnknow.


    d'ou ma question :

    y a t il une différence entre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    IUnknow(FBaseItems)._Release;
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    (FBaseItems as IUnknow)._Release;

  13. #33
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    Citation Envoyé par sjrd Voir le message
    La solution donnée initialement, avec des record avancés, est sympathique. Il n'en demeure pas moins que la bonne solution est en effet d'appeler _Release après l'affectation, mais aussi _AddRef avant que cette variable ne soit modifiée (ou remise à nil, ce qui inclut la libération de son objet porteur).
    une autre solution est celle utilisée par Codegear dans l'implementation de TAggregatedObject : utiliser un pointeur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    constructor TAggregatedObject.Create(const Controller: IInterface);
    begin
      // weak reference to controller - don't keep it alive
      FController := Pointer(Controller);
    end;
    c'est ce mécanisme via pointeur qu'a repris Suryavarman dans sa solution
    via un Record, mais on peut tout à fait réutiliser ce principe dans forcément utiliser la structure de Suryavarman, qui n'est utilisable que dans les versions de delphi supportant la surchage d'opérateurs.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    procedure TChild.setParent(AParent:IParent);
    begin
     fParent:=Pointer(AParent as IUnknow); // si on veut on peut mettre autre chose que IUnknow, 
                                          //mais il faudra alors utiliser la même Interface dans GetParent
    end;
    par contre obligé d'avoir ensuite un accesseur pour retrouver notre interface :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    procedure TChild.GetParent:IParent;
    begin
     result:=IUnknow(fParent);
    end;
    ou bien de toujours utiliser fPArent comme ca : IUnknow(fParent)
    dans l'implementation de la classe.

  14. #34
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    attendez là, moi y'a un truc que je comprend pas...

    si je tape ceci dans Delphi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    type
     IMonMachinAMoi=interface
      procedure SayHello;
     end;
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
     i:IMonMachinAMoi;
    begin
     i.
    end;
    juste après "i." j'ai un popup avec SayHello, QueryInterface, _AddRef, _Release et alors c'est quoi cette histoire de caster IParent en IUnknown ?!

    TOUTES les interfaces possèdent _AddRef, _Release et QueryInterface ! d'ailleurs "as" n'est qu'une autre façon d'écrire QueryInterface !
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  15. #35
    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
    Citation Envoyé par Paul TOTH Voir le message
    attendez là, moi y'a un truc que je comprend pas...

    TOUTES les interfaces possèdent _AddRef, _Release et QueryInterface ! d'ailleurs "as" n'est qu'une autre façon d'écrire QueryInterface !
    Euh, ça me rappele le sujet sur l'héritage d'interface, parfois certains se compliquent la vie, c'est comme ça !

    Citation Envoyé par Suryavarman Voir le message
    ... reléguer la responsabilité de la gestion mémoire, de sa manipulation, etc... à un interface.
    Ah, ouais, quand on utilise un mécanisme de programmation pour une utilisation qui n'a aucun rapport avec ce quoi il est prévu, je comprends que l'on ne soit pas sur la même longueur d'onde ... bon, dans la suite de ton message il me semble que tu utilise quand même l'interface pour faire de l'inter-opérabilité ...

    Maintenant, il aurait été plus simple de "cloner" ou de "détacher" un sous-arbre, ta fonction renvoie un arbre, à un moment donné le client souhaite récupérer qu'une partie de l'arbre et bien, tu fais une méthode "Detach" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    INode = Interface
      procedure Detach();
     
    procedure TNodeImpl.Detach();
    begin
      FParent := nil;
    end;
    dans le client
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      NodeEnfant := NodeRoot.Enfants[0].Enfants[1] ....;
      NodeEnfant.Detach();
      NodeRoot := nil; // Parent libéré, le NodeEnfant devient le nouveau Root
    Voilà, rendre tous les mécanismes implicites, ce n'est pas malin parfois, en tout cas, moi c'est l'inverse, j'aime avoir la maitrise sur ce que j'utilise ... si un client garde une instance de NodeEnfant sans le détacher, eh bien, il ne libère pas le parent, mais ce n'est pas grave, il le sera tôt ou tard lorsque le dernier enfant sera mis à nil, pas de fuite, juste de la mémoire utilisée inutilement, ... on en revient à ce que je disais ... tu cherche la petite bête où il n'y a en a pas, et je confirme, tu prends vraiement l'utilisateur de ta classe pour un débil profond, mais c'est dans la logique du garbage collector après tout ...




    +1 pour Franck SORIANO avec le Release !
    C'est si simple, cela rend le fonctionnement implicite que souhaite Suryavarman même si l'explicite pour moi est la clé de la transparence ...
    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

  16. #36
    Membre actif Avatar de Suryavarman
    Homme Profil pro
    Développeur 3D
    Inscrit en
    Mai 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur 3D
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Mai 2006
    Messages : 233
    Points : 245
    Points
    245
    Par défaut
    ... tu cherche la petite bête où il n'y a en a pas, et je confirme, tu prends vraiement l'utilisateur de ta classe pour un débil profond, mais c'est dans la logique du garbage collector après tout ...
    Non c'est sur quoi je bosse en ce moment. L'arbre n'est qu'un exemple.

    pas de fuite, juste de la mémoire utilisée inutilement
    1 - Le reportmemoryleak dit l'inverse
    2 - Là en ce moment ce sont des objets 3D, des textures etc qui sont dans mon arbre. Je te laisse imaginer le problème.
    3 - Le guss prend mon tree, met les objets dedans il fait mumuse avec, ferme le programme. Le guss prend ton tree, vois le Detach regarde comment ça marche, veille à ne pas libérer en passant par une autre interface, avant de quitter le programme il s'assure de faire Detach. Tu va dire c'est pas trop grave, je dirais oui...mais autant exploiter le langage à fond (pour la beauté du code )

    Si t'aimes pas l'automatisme, si t'aime pas la RTTI , si tu veux tout maîtriser et permettre de tout maîtriser---> Pourquoi avoir choisi Delphi ? Car tu peux voir comment c'est fais à l'intérieur ?
    Bein si c'est bien fait il n'y a pas à s'en inquiéter. Si ma structure est bien faite j'aurais plus à m'en soucier. Les petites bêtes...moins y en a mieux je me porte. Et plus je suis productif.
    "Quand le monde est dangereux, l'humilité est un facteur de longévité." ( Baxter "Evolution" )

  17. #37
    Membre éclairé 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
    Points : 736
    Points
    736
    Par défaut
    Citation Envoyé par Paul TOTH
    attendez là, moi y'a un truc que je comprend pas...
    toutes interfaces hérite de IInterface et posséde les méthodes QueryInterface ...
    mais le caste est necessaire si la reference est du type pointer et non du type interface.
    Akim Merabet

  18. #38
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Euh, ça me rappele le sujet sur l'héritage d'interface, parfois certains se compliquent la vie, c'est comme ça !
    en effet.. Hop IUnknow inutile viré...
    EDIT : inutile je précise dans le code où la classe est TBaseItem, mais effectivement indispensable avec le pointeur (mon exemple suivant)...


    ...je serais presque tenté d'exposer le code entier de ma classe TBaseItems (et son TBaseItem associé) pour voir si vous décelez d'autres trucs anormaux comme ca...

    ..en effet c'est une classe que j'utilise énormément désormais.

    ( alors qu'au départ je l'avais juste créée par curiosité : voir si j'arrivais à créer une classe comme TCollection mais manipulable que via des interfaces et avec un ref count automatique. )



    Citation Envoyé par Paul Toth
    d'ailleurs "as" n'est qu'une autre façon d'écrire QueryInterface !
    Ok donc : IMonInterface as IUneAutre peut marcher même si les 2 interfaces n'ont rien à voir entre elles (du moment que la classe utilisée les implémente toutes les 2)

    alors que IUneAutre(IMonInterface) ne marchera que si IMonInterface descend de IUneAutre, c'est bien ca ?

  19. #39
    Membre éclairé 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
    Points : 736
    Points
    736
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    IMonInterface as IUneAutre
    la tu interroge


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    IUneAutre(IMonInterface)
    la t sur donc tu caste

    non?
    Akim Merabet

  20. #40
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    une autre solution est celle utilisée par Codegear dans l'implementation de TAggregatedObject : utiliser un pointeur.
    Ca marche mais c'est de la haute bidouille. Tu cast l'interface en pointeur pour tromper le compilateur pour qu'il n'appelle pas AddRef implicitement...

    j'ai un popup avec SayHello, QueryInterface, _AddRef, _Release et alors c'est quoi cette histoire de caster IParent en IUnknown ?!

    TOUTES les interfaces possèdent _AddRef, _Release et QueryInterface ! d'ailleurs "as" n'est qu'une autre façon d'écrire QueryInterface !
    C'est un truc sur lequel j'ai toujours eu un doute. D'un point de vu théorique, une interface c'est juste une déclaration de prototypes de méthodes.
    Sauf que l'implémentation qui en a été faite par Borland dans Delphi, c'est uniquement pour implémenter des objets COM.
    Ensuite ils ont détourné cette implémentation pour utiliser des interfaces sur autre chose.
    Donc ce que tu es en train de dire, c'est qu'en Delphi, toute interface dérive implicitement de IUnknown.

    Sinon Suryavarman, le comptage de référence a ces limites. Ce que tu veux c'est un garbage collector...

Discussions similaires

  1. [PageControl] Raccourcis claviers court-circuités
    Par Manopower dans le forum Composants VCL
    Réponses: 8
    Dernier message: 04/09/2009, 16h52
  2. [Disque Dur] Problème de court-circuit
    Par saih_tam dans le forum Composants
    Réponses: 9
    Dernier message: 20/05/2009, 15h03
  3. Réponses: 2
    Dernier message: 06/07/2007, 10h41
  4. Réponses: 13
    Dernier message: 09/04/2007, 13h20
  5. Réponses: 4
    Dernier message: 16/03/2004, 18h03

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