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 :

Quelle est la logique de l'ordre d'initialisation des unités dans D7


Sujet :

Langage Delphi

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Points : 61
    Points
    61
    Par défaut Quelle est la logique de l'ordre d'initialisation des unités dans D7
    Bonjour,

    J'ai un problème très simple dont voici un résumé :

    J'ai deux unités : "UnitSub" et "UnitMain".
    "UnitMain" possède une section d'initialisation créant un objet globale utilisé par un objet globale de "UnitSub" lui-même créé dans la section initialisation de cette dernière unité. Suis-je clair ?

    Pour résumer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Unit UnitMain;
     
    initialization
       MainObj:= TMainObj.Create;
     
    finalization
       MainObj.Free;

    Pour résumer :

    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
    Unit UnitSub;
     
    interface
     
    uses 
       UnitMain;
     
    constructor TSubObj.Create;
    begin
       FData:= MainObj.Data;
    end;
     
    initialization
       SubObj:= TSubObj.Create;
     
    finalization
       SubObj.Free;


    Hors à l'exécution de mon programme je vérifie que la section initialization de "UnitSub" est appelé avant la section initialization de "UnitMain". Cela provoque donc une violation d'accès.

    Pourquoi ne suis-je pas assuré que UnitMain soit initialisée avant puisqu'elle apparait dans la section "interface/uses" de mon unité "UnitSub" ??...

    Cela ne me semble pas "normal" et m'ennuie beaucoup car remet en cause la logique que je pensais être la bonne jusqu'à présent, et du même coup l'intégrité de mes sections "initialization" et "finalization" de bon nombre de mes unités...

  2. #2
    Expert éminent sénior
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Points : 10 008
    Points
    10 008
    Par défaut
    Salut

    Très certainement parce que dans la liste des uses de la section interface de UnitMain est inclus UnitSub.

    L'appel aux sections initialization respecte l'ordre d'énumération des unités de la clause uses.

    @+ Claudius

  3. #3
    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
    Tient lit ce sujet http://www.developpez.net/forums/d69...on-impossible/

    j'ai découvert qu'en debug, l'ordre de initialization change, en fait l'unité en cours de modification est recompilée et relinkée avec les DCU des autres unités, du coup la séquence des uses n'est plus dans le même ordre, il faut utiliser une méthode de classe pour instancier la singleton et ne pas utiliser initialization pour un singletion
    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

  4. #4
    Expert éminent sénior
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Points : 10 008
    Points
    10 008
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Je pense qu'il l'a déjà lu puisqu'il est l'auteur de cette discussion.

  5. #5
    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
    ça c'est Fort !
    Ben, il n'a peut-être pas lu toute ma réponse à l'époque, puisque un peu hors-sujet
    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

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Points : 61
    Points
    61
    Par défaut
    Merci pour vos réponses,

    En fait, étant donné que Delphi supporte des inter-dépendances entre unités vie les différentes sections "uses" (celle de "interface" et celle de "implementation") cela entraine forcément des cas où on ne peut déterminer précisément l'ordre d'initialisation des unités (à moins d'utiliser un outil comme "http://www.ciuly.com/tools/programming/pisa/index.html").

    Ce n'est donc pas aussi simple que la logique bête qui était la mienne "si j'utilise une unité, elle sera initialisée avant moi". Ce n'est pas possible puisque justement Delphi permet l'interdépendance entre 2 unités, d'où mon cas de plantage...

    Cela signifie qu'il faut prévoir le coup dans toutes les sections d'initialisation/finalization, ouch !!


    Mon idée est d'écrire des méthodes globale "InitUnit" pour toutes mes unités possédant des sections "initialization", et d'appeler cette méthode à chaque fois dans cette section. Et lorsque je construit un objet globale je devrai vérifier que celui-ci n'est pas déjà instancié avant (il faut donc un "FreeAndNil" et non plus un ".Free" seulement). Et si sa construction dépend d'un autre objet globale d'une autre unité alors il faut appeler explicitement le "InitUnit" de cette unité.

    C'est pas très clair, mais en gros j'aurai le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Unit UnitMain;
     
    procedure InitUnit;
    begin
       if ( not Assigned( MainObj ) ) then
          MainObj:= TMainObj.Create;
    end;
     
    initialization
       InitUnit;
     
    finalization
       FreeAndNil( MainObj );
    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
     
    Unit UnitSub;
     
    interface
     
    uses 
       UnitMain;
     
    procedure InitUnit;
    begin
       // Notre initialisation d'unité dépend de l'initialisation de l'unité "UnitMain"
       UnitMain.InitUnit;
     
       if ( not Assigned( SubObj ) ) then
          SubObj:= TSubObj.Create;
    end;
     
    constructor TSubObj.Create;
    begin
       FData:= MainObj.Data;
    end;
     
    initialization
       InitUnit;
     
    finalization
       FreeAndNil( SubObj );

    Je pense que c'est le comportement à adopter pour s'assurer que les unités s'initialisent toujours correctement lorsqu'on a un projet trop complexe pour s'assurer du bon ordre d'utilisation de ses unités.


    ShaiLeTroll> Oui j'ai remarqué aussi que l'ordre d'initialisation des unités changeait en mode debug après recompilation d'unité. C'est assez gênant car j'utilise des unités qui n'acceptent pas cela (FastMM par exemple).

  7. #7
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 557
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 557
    Points : 3 938
    Points
    3 938
    Par défaut
    Salut à tous

    Je connais une solution simple pour s'affranchir de la clause initialization s'il s'agit de créer un objet. En fait, je crée l'objet dès que j'en ai besoin en passant par une fonction, l'usage de la clause initialization n'est alors plus justifié. Ma solution est pratique si la construction de l'objet nécessite pas de paramètres, dans le cas contraire cela peut sans doute amener des complications.

    En reprenant et adaptant ton exemple

    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
     
    Unit UnitMain;
     
    interface 
     
    function MainObj: TMainObj;
     
    implementation
     
    var 
      FMainObj: TMainObj; 
     
    function MainObj: TMainObj;
    begin
      if not Assigned(FMainObj) then
        FMainObj := FMainObj.Create;
      Result := FMainObj;	
    End;
     
    initialization // sinon cela ne compile pas 
       ;           // sous Delphi 7 (version que j'utilise)
     
    finalization
       FMainObj.Free; // Ca marche toujours
     
    END.

    Pour SubMain, Je reprend ton code, mais je n'ai pas tous les éléments pour le faire, il est peut-être incomplet.
    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
     
    Unit UnitSub;
     
    interface
     
    uses 
       UnitMain;
     
    constructor TSubObj.Create;
    begin
       FData:= MainObj.Data;
    end;
     
    initialization
       SubObj:= TSubObj.Create;
     
    finalization
       SubObj.Free;
    J'espère que ma solution te sera utile.

    Cdlt

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Points : 61
    Points
    61
    Par défaut
    Effectivement c'est une solution qui fonctionne très bien également, à la limite je dirai même qu'on pourrait pousser en ne créant plus d'objets dans "Initialization" et n'utilisant que des accès via fonction pour tous les objets dont on a une instance globale utilisé par d'autres unités. C'est une autre façon de faire, plus simple, mais qui peut-être moins optimale dans le cas d'utilisation de l'instance un très grand nombre de fois par seconde (boucle interne, etc...).
    J'avoue que l'idée de passer par une fonction systématiquement me dérange un peu, mais c'est finalement plus propre. Alors j'hésite à changer...

  9. #9
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 557
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 557
    Points : 3 938
    Points
    3 938
    Par défaut
    Salut

    Pour le cas de la boucle, tu peux toujours affecter le résultat de la fonction (la référence de ton objet) dans une variable locale, 4 octets de plus dans la pile n'est pas catastrophique.

    La méthode que je t'ai proposée suppose aussi que l'on ne souhaite pas changer la référence de l'objet (lecture seule).

    Elle a cependant l'avantage de la facilité.

    Cdlt

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Points : 61
    Points
    61
    Par défaut
    Bien sur, mais il faut y penser (pour peu qu'on ait oublié ou qu'on fasse pas attention au fait que ce soit une fonction) ;-) !

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 10/07/2012, 11h48
  2. Réponses: 4
    Dernier message: 15/05/2010, 09h24
  3. [RMAN] RUN ou pas RUN : quelle est la logique ?
    Par Pomalaix dans le forum Administration
    Réponses: 1
    Dernier message: 05/12/2007, 18h06
  4. Réponses: 1
    Dernier message: 09/06/2006, 12h04
  5. [WHERE] Quelle est l'incidence de l'ordre des filtres ?
    Par MashiMaro dans le forum Langage SQL
    Réponses: 5
    Dernier message: 25/12/2005, 18h36

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