Publicité
+ Répondre à la discussion
Page 1 sur 2 12 DernièreDernière
Affichage des résultats 1 à 20 sur 23
  1. #1
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 098
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 098
    Points : 5 752
    Points
    5 752

    Par défaut [FAQ] Différence entre Init() et ctor

    Bonjour,

    je propose un ajout dans la faq "Quelles sont les différences fondamentales entre le constructeur d'une classe et sa méthode Init() ?"

    Il est écrit qu'il existe 2 solutions.
    J'en vois une troisième: le scope guard.

  2. #2
    Expert Confirmé Sénior

    Homme Profil pro Pierre
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    2 228
    Détails du profil
    Informations personnelles :
    Nom : Homme Pierre
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : juin 2007
    Messages : 2 228
    Points : 5 178
    Points
    5 178

    Par défaut

    Où donc veux-tu en venir?
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • La plus sotte des questions est celle qu'on ne pose pas.

    Pour faire des graphes, essayez yEd.

  3. #3
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 098
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 098
    Points : 5 752
    Points
    5 752

    Par défaut

    Il est écrit:
    Si init lève une exception, la mémoire (ou autres ressources) allouée pour t n'est jamais libérée
    Le scope guard est également une solution qui permet de régler ce problème (bien que ce ne soit pas fait pour ça à l'origine):
    Code :
    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
    class ScopeGuard
    {
    public:
      ScopeGuard () 
       : engaged_ (true) 
      {}
     
      ~ScopeGuard ()  
      { 
        if (engaged_) 
         { /* libération des ressources ici */} 
      }
     
      bool init( /* params */ )
      {
        // initialisation et acquisition ici, avec une gestion correcte des allocations (et libération en cas d'échec)
     
        // si tout s'est bien passé
        engaged_ = true; 
        return true;
      }
     
    private:
      bool engaged_;
    };
    C'est que parfois (souvent même j'ai l'impression) on ne peut pas acquérir tout dès le constructeur.

  4. #4
    Expert Confirmé Sénior

    Homme Profil pro Pierre
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    2 228
    Détails du profil
    Informations personnelles :
    Nom : Homme Pierre
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : juin 2007
    Messages : 2 228
    Points : 5 178
    Points
    5 178

    Par défaut

    Si tu ne peux pas tout acquérir dès le constructeur, c'est que tu veux construire une voiture sans avoir fabriqué ou acheté le moteur.

    Ce que tu ne peux pas avoir automatiquement, demande le en argument, et tout devient simple.
    Si ce n'est pas encore le cas, raiie-le (*).
    Si c'est encore impossible, je pense que l'architecture est mal pensée.

    Je m'explique:

    Si j'ai besoin d'initialiser quelque chose que j'ai déjà construit, dans quel état était-il?

    Un objet est toujours dans un état connu et utilisable, il doit être construit ou ne pas être.


    * tiens, je l'aime bien, mon néologisme
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • La plus sotte des questions est celle qu'on ne pose pas.

    Pour faire des graphes, essayez yEd.

  5. #5
    Inactif


    Homme Profil pro
    Inscrit en
    novembre 2008
    Messages
    5 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : novembre 2008
    Messages : 5 308
    Points : 15 141
    Points
    15 141

    Par défaut

    C'est pas une troisième méthode, c'est une implémentation particulière de init().

    Qui peut rapidement poser des problèmes : si tu as plusieurs variables à initialiser, tu devras créer une variable bool pour chaque variable membre que tu veux initialiser, ce qui sera vite ingérable.

    La solution, c'est le RAII, c'est à dire initialiser dans le constructeur (et comme le dit leternel, si c'est pas possible, voir s'il n'y a pas un problème de conception).
    Et utiliser des pointeurs intelligents (voir pas de pointeur) pour les variables membres.

    Par contre, il faudra quand même mettre à jour cette faq (en fait, l'ensemble de la faq) pour le C++11 (auto_ptr...)

  6. #6
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 098
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 098
    Points : 5 752
    Points
    5 752

    Par défaut

    @leternel: J'ai du mal à comprendre ton message...
    Selon toi, il serait interdit de construire un objet partiellement puis de le remplir ensuite par aggregation? L'idiome scope guard n'a donc pas lieu d'être?

  7. #7
    Inactif


    Homme Profil pro
    Inscrit en
    novembre 2008
    Messages
    5 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : novembre 2008
    Messages : 5 308
    Points : 15 141
    Points
    15 141

    Par défaut

    Pas interdit, le C++ est un langage permissif...
    Mais non respectueux du RAII, donc moins sur, moins robuste, moins lisible, etc

    L'approche C++ : le RAII
    Architecture Logicielle & Développement - RAII !

  8. #8
    Inactif


    Homme Profil pro
    Inscrit en
    novembre 2008
    Messages
    5 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : novembre 2008
    Messages : 5 308
    Points : 15 141
    Points
    15 141

    Par défaut

    Citation Envoyé par r0d
    C'est bon, je sais ce qu'est le RAII quand-même.
    J'ai parfois l'impression que nous ne vivons pas sur la même planète. C'est super tous ces idiomes et partons, je suis le premier à en défendre l'usage. Mais dans la vrai vie on ne peut pas toujours faire ce qu'on veut, en particulier lorsqu'on travaille sur de l'existant. Et c'est la raison pour laquelle ce type de solutions existent.
    Pas de problème, c'est bien le même monde : je passe beaucoup plus de temps à maintenir de l'existant que de partir d'une feuille (de code) vierge

    Après, effectivement, si on peut pas modifier un code existant pour mettre en place le RAII, que l'on peut pas utiliser des pointeurs intelligents (fournit pas le C++11, boost, Qt, ou même que l'on aurait créé), cela devient compliqué à faire du code robuste.

    Le code que tu présentes posera vite des problèmes à mon sens (peut être d'autres auront un avis différents). Pour les objets complexes, j'aurais tendance à préféré des DP composite, builder, etc. Ou un DP wrapper pour sécuriser/isoler un code non robuste (typiquement une lib C utilisée en C++), etc


    Pour revenir plus spécifiquement à la FAQ, il me semble que c'est pas une correction à faire (parce que c'est pas une troisième solution, mais une implémentation spécifique de init ; et qu'il faut bien faire des choix quand au contenu de la faq)

  9. #9
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 758
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 758
    Points : 17 270
    Points
    17 270

    Par défaut

    Salut,

    En fait, nous pourrions peut etre en effet parler du scope guard, tout en précisant clairement qu'il s'agit d'une manière de travailler qui devrait être réservée au cas "exceptionnel" dans lequel on n'a pas d'autre solution (comme la maintenance d'un code existant), mais qui est symptomatique d'un problème de conception à la base.

    Je suis le premier à prôner le fait qu'un objet se doit d'être directement dans un état cohérent dés la fin du constructeur, mais j'ai aussi rencontré suffisamment de code pour savoir qu'il est parfois difficile de faire en sorte que ce soit toujours le cas
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  10. #10
    Expert Confirmé Sénior

    Homme Profil pro Pierre
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    2 228
    Détails du profil
    Informations personnelles :
    Nom : Homme Pierre
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : juin 2007
    Messages : 2 228
    Points : 5 178
    Points
    5 178

    Par défaut

    Personnellement, au boulot, je refuse systématiquement d'écrire du code qui n'est pas "constructor coherent".
    Et chaque fois, c'est accepté, et je fais sauter un millier de lignes de code (oui, le projet est monstrueux…)

    D'ailleurs, en général, quand j'en parle tous les développeurs semblent d'accord pour reconnaître que le code est "mal écrit" dans ces portions.

    La seule "exception" est les "arguments nommés", que j'utilise pour la construction de requete sql, par exemple.
    Encore que, "construction en cours" peut-être vu comme un état valide d'un "RequestBuilder"
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • La plus sotte des questions est celle qu'on ne pose pas.

    Pour faire des graphes, essayez yEd.

  11. #11
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 098
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 098
    Points : 5 752
    Points
    5 752

    Par défaut

    Il y a quelque chose qui m'échappe dans tout ça.
    Déjà, dans ladite faq, je lis:
    Dans certains cas, on n'a pas assez d'infos à la construction de l'objet pour tout initialiser [...]
    Selon vous, cette phrase est à bannir? Et donc toute la faq? Puisque si je comprend bien, vous êtes en train de dire que la fonction init() ne devrait pas exister? Répondez-moi s'il vous plait, je ne comprend pas votre position.

    Vous n'êtes jamais tombé sur des problèmes où vous n'avez pas ce qu'il faut pour construire un objet complètement au moment où l'on a pourtant besoin de lui?

    gbdivers par exemple, je lis que tu es bio-informaticien. Tu dois bien avoir rencontré des problèmes de data-mining où tu dois construire une structure à partir de set de données partiellement complets non? Et encore ça s'est rien, le vrai problème c'est lorsqu'on doit construire un modèle à partir de ces données incomplètes et qu'on ne sait pas à l'avance de quelle façon on va construire cet objet.

    Quant à "supprimer des milliers de ligne de code", parfois c'est juste pas possible. Par exemple (et sans parler du cas - pourtant fréquent - du problème de temps), lorsque ces milliers de lignes de code effectuent un traitement tellement complexe qu'il nous faudrait des années pour seulement comprendre ce que fait ce code.

  12. #12
    Inactif


    Homme Profil pro
    Inscrit en
    novembre 2008
    Messages
    5 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : novembre 2008
    Messages : 5 308
    Points : 15 141
    Points
    15 141

    Par défaut

    A voir tes questions, je crois que l'on pas été assez précis et exacte sur les explications.

    un objet se doit d'être directement dans un état cohérent dés la fin du constructeur
    En fait, la construction est différent de l'initialisation. La fonction init est surement mal nommé, son but n'est pas d'initialiser la classe (c'est ce que fait assign pour vector par exemple), mais de la "construire" (selon la définition de koala01, en particulier que l'invariant de classe soit respecté à la fin du constructeur)
    Il n'est pas aberrant de créer un conteneur vide et de le remplir avec des push_back, on sait bien qu'il n'est pas possible dans la plupart des cas de créer le vecteur directement rempli.

    Ici on parle bien d'utiliser une fonction init en remplacement du constructeur, donc une fonction qui chargée de mettre la classe dans un étant cohérent. Ce qui implique que l'objet n'est pas dans un étant cohérent entre l'appel du constructeur et l'appel de init (si c'est pas le cas, alors c'est que le constructeur a fait son boulot et que la fonction init n'est pas en remplacement du constructeur, mais une vraie fonction d'initialisation)

    Il faut peut être reformuler certaines phrases...

  13. #13
    Expert Confirmé Sénior
    Avatar de Luc Hermitte
    Homme Profil pro Luc Hermitte
    Développeur informatique
    Inscrit en
    août 2003
    Messages
    4 743
    Détails du profil
    Informations personnelles :
    Nom : Homme Luc Hermitte
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : août 2003
    Messages : 4 743
    Points : 7 819
    Points
    7 819

    Par défaut

    auto_ptr<> est une capsule à la RAII. Aujourd'hui on dirait unique_ptr. C'est un scoped_guard. Un peu particulier certes, mais cela en est un. C'est ici un détail par rapport à comment écrire cette sorte de factory-method qui fait construction + post-init polymorphiqme.

    Sinon, bonne idée que de déterrer ce point de FAQ car il n'adresse pas clairement ce qui est vraiment important.

    init() est un truc hérité de l'enseignement syntaxique par delta du C++ (j'invente les mots ; mais ils viennent d'une rumination pour une présentation que j'ai faite dans la boite pour inciter de migrer du C++ historique au C++ moderne). Au départ le C dont on fait vite le tour de la syntaxe. Le Pascal omniprésent dans l'éducation (chez nous du moins). Et des profs dans les années fin 80 à 90+ qui veulent présenter le C++.
    Donc il partent du C. Voilà une structure, on en fait un premier objet. Souvenez-vous les structures il faut les initialiser. Pouf une fonction init(). Ils continuent à présenter divers trucs et puis à un moment ils reviennent sur l'initialisation des données (notez le soucis au passage : la POO part d'une agrégation de données, et non de services rendus) et disent: ouais mais en fait il y a un truc fait pour initialiser -> les constructeurs.
    [notez l'approche itérative, d'où le "delta", qui ne s'intéresse qu'à présenter la syntaxe]

    Sauf que c'est déjà trop tard, les élèves ont eu deux semaines de TP entre temps à avoir utilisé des fonctions init() qui semblent remplir le besoin. Ils ont déjà pris la mauvaise habitude et sans même savoir pourquoi c'est une mauvaise habitude, parce que l'on ne leur a jamais parlé de cet invariant dynamique/"structurel" (pas le bon mot)

    En effet, la fonction init() oblige à gérer l'invariant "objet utilisable" de façon dynamique : avec un membre isReady/isInitialized, et un test de cette variable en début de chaque fonction. Tandis que l'approche constructeur nous assure un invariant statique : "par construction" (souvenez-vous des démonstrations en maths, c'est le même "par construction"), nous sommes assurés que si l'objet existe alors il est utilisable => pas de test à faire!

    Ce qui me fait penser à cette analyse d'une interview de Stroustrup, où il est cité à dire: http://www.theregister.co.uk/2012/12...n_c_plus_plus/
    Citation Envoyé par Stroustrup
    I try to focus on things that lead to correct programs fairly easily. I emphasise the use of constructors to establish invariance, to acquire resources, destructors for cleaning up [...]
    L'invariance. C'est la clé du pourquoi les fonctions init c'est mal.

    Au final, je vois deux intérêts à init() :
    - la post-initialisation polymorphique, dont le point de FAQ parle
    - le code pré-exceptions -> je vous renvoie aux règles de codage chez google qui interdisent les exceptions (car base de code sans exceptions trop volumineuse pour changer ça) et qui demandent donc à utiliser des fonctions init().
    Mais init() reste le cousin pauvre du constructeur. À bannir par défaut.

    [Ce peut valoir le coup d'insister sur cette histoire d'invariance dans le point de FAQ]
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  14. #14
    Inactif


    Homme Profil pro
    Inscrit en
    novembre 2008
    Messages
    5 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : novembre 2008
    Messages : 5 308
    Points : 15 141
    Points
    15 141

    Par défaut

    et un test de cette variable en début de chaque fonction
    Juste une remarque. Si ce test est réellement effectué pour toutes les fonctions, alors a priori, la classe est toujours cohérente (on a bien la validation systématique faite pas le concepteur de la classe et pas par l'utilisateur, simplement l'invariant de classe I devient "si isInitialized alors I, sinon rien" et il est toujours respecté, pas d'états et de comportements indéterminés)

    En pratique, c'est jamais fait comme ça (surcout, oubli), d'ou la nécessité de l'appel d'init par l'utilisateur (et la faq dans ce sens, avec la phrase "l'utilisateur doit l'appeler manuellement (risque d'oubli)" sur le risque d'erreur par l'utilisateur)

  15. #15
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 758
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 758
    Points : 17 270
    Points
    17 270

    Par défaut

    Citation Envoyé par gbdivers Voir le message
    Juste une remarque. Si ce test est réellement effectué pour toutes les fonctions, alors a priori, la classe est toujours cohérente (on a bien la validation systématique faite pas le concepteur de la classe et pas par l'utilisateur, simplement l'invariant de classe I devient "si isInitialized alors I, sinon rien" et il est toujours respecté, pas d'états et de comportements indéterminés)

    En pratique, c'est jamais fait comme ça (surcout, oubli), d'ou la nécessité de l'appel d'init par l'utilisateur (et la faq dans ce sens, avec la phrase "l'utilisateur doit l'appeler manuellement (risque d'oubli)" sur le risque d'erreur par l'utilisateur)
    En fait, il s'agit plus d'une précondition pour tout usage d'un objet autre que l'appel à init et d'une postcondition pour le fait d'appeler init

    Mais la question se pose alors dans ces termes :
    Que va-t-il se passer si la précondition n'est pas respectée
    La réponse classique à cette question est généralement
    Ben, ca, mon vieux, tant pis pour toi... avec beaucoup de chance, ca passera, sinon...
    Et on l'en revient à un problème similaire à ce qui fait que l'on préfère les références aux pointeurs "chaque fois que possible" car cela sous entend que toute fonction commence par ... un gros test d'initialisation (le lien entre un if(ptr) et un if (object.initialized() ) est flagrant )

    Edit Cependant, on ne peut pas prétendre qu'un objet sur lequel init n'aurait pas été appelé soit "cohérent".

    La preuve en est que, si init n'a pas été appelée sur un objet, on ne peut absolument pas préjuger du résultat et qu'il faut donc s'assurer de la cohérence de l'objet au travers du test
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  16. #16
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 098
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 098
    Points : 5 752
    Points
    5 752

    Par défaut

    Citation Envoyé par gbdivers Voir le message
    A voir tes questions, je crois que l'on pas été assez précis et exacte sur les explications.
    Il me semble, en effet. D'ailleurs, vous ne répondez pas à mes questions.

    Je vais essayer de trouver une formulation avec laquelle nous soyons tous d'accord: l'init c'est comme les pointeurs, à n'utiliser que lorsqu'on ne peut pas faire autrement (formulation qui sous-entend que, parfois, on ne peut peut pas faire autrement).

    Après, Luc a raison sur le fait que derrière cette discussion, il y a un problème plus théorique concernant l'état d'un objet. Je suis bien incapable de formuler cela clairement, mais en gros, je pense que ce qui est important c'est l'état de l'objet (à un instant donné), et pas la façon dont l'objet est construit et/ou modifié. Donc l'invariance, mais peut-être pas uniquement (d'ailleurs, en parlant d'invariance, il serait peut-être bien de parler des assertions dans la faq?).

    Il y a également un problème de définitions:
    - Quand est-ce qu'un objet est "utilisable"? En effet, on peut imaginer un objet construit partiellement, avec une sémantique telle que si certaines partie manquent cela ait du sens (un exemple: sachant que telle donnée est manquante, cela permet de se situer dans l'arbre d'un traitement sur lequel on a pas le contrôle. D'ailleurs, de façon plus globale, l'absence de donnée a en fait parfois du sens.).
    - Qu'est-ce que l'invariance en c++? Je n'ai trouvé aucune définition qui me convienne. Une classe (un type en général) n'est pas un invariant en soi, mais elle définit des invariants. Mais comment appréhender ces invariants lorsqu'on a une classe qui évolue (par exemple une machine à état).
    - Qu'entendez-vous par "constructor coherent"?

    Enfin, un point qui n'est toujours pas clair pour moi: quid des constructeurs pas défaut? On est très souvent obligé de passer par un constructeur par défaut (stockage dans un conteneur template, basiquement). Est-ce que, dans ce cas, une fonction init() n'est pas envisageable? Un exemple de code pour illustrer ma question:
    Code :
    1
    2
    3
    4
    5
    6
    main()
    {
      std::vector<MyObject> v(5);
      // arrivé là, nos 5 objets sont déjà construits via le default ctor. 
      // Ils ne sont pas forcément utilisables directement pour autant
    }

  17. #17
    Expert Confirmé Sénior

    Homme Profil pro Pierre
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    2 228
    Détails du profil
    Informations personnelles :
    Nom : Homme Pierre
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : juin 2007
    Messages : 2 228
    Points : 5 178
    Points
    5 178

    Par défaut

    Code :
    1
    2
    3
    4
    5
    6
    main()
    {
      std::vector<MyObject> v(5);
      // arrivé là, nos 5 objets sont déjà construits via le default ctor. 
      // Ils ne sont pas forcément utilisables directement pour autant
    }
    S'ils ne sont pas utilisables, c'est parce que le constructeur par défaut est pourri, car il ne fait pas ce qu'il faut.

    Si tu fais un std::vector<char> v(5); ton vector contient cinq char, pleinement utilisables.

    un objet est utilisable si toute fonction membre est appelable et n'échoue pas hors interface.

    Par exemple, si tu as un std::fstream, il est forcément utilisable. Sinon, le constructeur aurait throwé, et tu n'aurais pas ton fstream.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • La plus sotte des questions est celle qu'on ne pose pas.

    Pour faire des graphes, essayez yEd.

  18. #18
    Expert Confirmé Avatar de Flob90
    Homme Profil pro Florian Blanchet
    Etudiant en Optique
    Inscrit en
    août 2004
    Messages
    1 328
    Détails du profil
    Informations personnelles :
    Nom : Homme Florian Blanchet
    Âge : 24
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Etudiant en Optique

    Informations forums :
    Inscription : août 2004
    Messages : 1 328
    Points : 2 961
    Points
    2 961

    Par défaut

    - Invariant : N'importe quel propriété P que doit vérifier un objet de type T.

    - propriété : N'importe quel assertion (vérifiable ? (*)) sur un objet.

    - ctor coherent : Dans le contexte, un constructeur qui, si aucune exception n'est lancée, va créer un objet respectant les invariants associés au type (sinon rien n'est crée).

    Au final l'intérêt pratique des fonctions init est assez faible je pense :
    - Pour le code interdit d'exception
    - Pour le besoin de ctor polymorphe comme l'a expliqué Luc, cependant je me demande si il existe autant de cas que ça où ce besoin est bien fondé et pas lié à une conception bancale.
    - En fonction à visibilité restreinte pour factoriser le code, inutile en C++11 (delegating ctor).

    Pour les exemples de BDD, data mining, etc, c'est quand même aux développeur de fixer les invariants de sa classe (tout en restant cohérant), il a aussi le pouvoir d'introduire des intermédiaires (aux invariants plus faible), au final je suis convaincu que l'on peut aboutir à des designs sur ces éléments sans avoir besoin d'init.

    (*) De manire "théorique" le vérifiable ne sert à rien, de manière pratique, le résultat d'une assertion non vérifiable ne doit pas avoir réellement d'impact.
    "We can solve any problem by introducing an extra level of indirection" Butler Lampson

    "N'importe quel problème peut être résolu en introduisant un niveau d'indirection supplémentaire" Butler Lampson (traduction libre)

  19. #19
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 098
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 098
    Points : 5 752
    Points
    5 752

    Par défaut

    Citation Envoyé par Flob90 Voir le message
    - Invariant : N'importe quel propriété P que doit vérifier un objet de type T.

    - propriété : N'importe quel assertion (vérifiable ? (*)) sur un objet.
    Je craint que cela ne suffise pas, du moins pas dans le domaine du développement logiciel. Prenons l'exemple d'un objet qui a deux états et une fonction doSomething(). Cette fonction fera des choses différentes selon l'état de l'objet; par conséquent, notre objet aura des propriétés différentes selon son état. Pourtant, au niveau du paradigme objet, le type MonObjet::doSomething() sera invariant (une fonction peut être considéré comme un type).

  20. #20
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 098
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 098
    Points : 5 752
    Points
    5 752

    Par défaut

    Citation Envoyé par leternel Voir le message
    un objet est utilisable si toute fonction membre est appelable et n'échoue pas hors interface.
    Si ladite fonction lance une exception, tu considères cela comme un échec?
    Si oui, étant donné que toute fonction peut potentiellement lever une exception, alors aucun objet n'est utilisable.

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
  •