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

C++ Discussion :

Init() vs Constructeur


Sujet :

C++

  1. #1
    r0d
    r0d est actuellement connecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 288
    Billets dans le blog
    2
    Par défaut Init() vs Constructeur
    Bonjour à tous,

    un petit problème de conception m'a amené à me poser la question suivante: Quelle sont les différences fondamentales entre le constructeur d'une classe et sa méthode Init()?

    Ce qui engendre tout un tas de questions:
    - Où doit-on faire l'allocation de mémoire pour les membres (tableaux, etc.)?
    - Si l'on a des paramètres à passer pour construire et/ou initialiser sa classe, doit-on plutôt les passer au constructeur ou la la méthode Init()?
    - Que doit-on mettre dans l'un et pas dans l'autre?

    Merci.

  2. #2
    Membre chevronné Avatar de xxiemeciel
    Inscrit en
    Juin 2005
    Messages
    371
    Détails du profil
    Informations forums :
    Inscription : Juin 2005
    Messages : 371
    Par défaut
    Salut,

    Personnellement je dirais que ca depend pas mal de ce que tu veux faire. Certaines classe peuvent avoir des membres dont elles n'ont pas la memoire a gerer, dans ce cas la destruction est laisser a celui qui l'a alloué.

    Sinon la plupart du temps tu alloues ta memoire dans le constructeur et tu laliberes dans le destructeur.

    Pour la methode init, elle est surtout utile lorsque le meme objet a besoin d'etre reutiliser plusieurs fois et que tu veux reinitialiser ton objet sans pour autant reallouer toute ta memoire. Ou tout simplement reinitialiser ton objet sans avoir a en instancier un nouveau.

    XXiemeciel

  3. #3
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Par défaut
    Salut.

    J'ai toujours des difficultés de choix entre initialiser dans le constructeur ou avoit une méthode d'initialisation.

    Lorsque tu utilises une méthode, tu as une valeur de retour que tu peux tester.
    Pour le constructeur, tu peux passer en paramètre une référence qui pourra faire office de valeur de retour et qui te permettra de savoir si ton objet est bien construit.

    Le problème est là, un objet peut ne pas être entièrement construit si une exception se produit. Tu peux alors te retrouver avec des fuites de mémoire, voir même un plantage, selon ta gestion d'erreurs.

    Personnellement, je choisi la sécurité et dans le constructeur, je fais des initialisations simples et sans risques (pointeur à NULL, assignation de valeur pour les types courants, etc...).

    Dans le livre "le langage C++", on te parle de ce problème, mais on ne te donne pas vraiment de solution. Tu as le choix, mais tu es prévenu.

  4. #4
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Le constructeur est une fonction spéciale appelée automatiquement à certains endroits, une fonction init n'est aucune sémantique spéciale, l'utilisateur doit l'appeler manuellement (risque d'oubli).

    En règle générale, je dirais qu'il faut utiliser uniquement un constructeur. Dans certains cas, on n'a pas assez d'infos à la construction de l'objet pour tout initialiser, d'où une fonction init, mais c'est assez rare.

    Pour signaler une erreur dans le constructeur, il peut lancer une exception, et dans ce cas, l'objet n'est pas construit du tout.

    S'il est bien programmé, cette tentative de construction n'aura pas alloué de resosurces sans les libérer. Sinon, ça peut poser des problèmes. Mais écrire un constructeur correctement vis à vis des exceptions est du même niveau de difficulté que d'écrire une fonction init correctement vis à vis des exceptions.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  5. #5
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 292
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    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 : 5 292
    Par défaut
    +1 à la réponse de Loïc.
    Je vois les fonctions init() comme un archaisme utilisé par certains qui tiennent à les présenter avant les constructeurs, et une nécessité dans les extrêmes rares cas où l'on a besoin de post-construction polymorphique -- si je puis dire.
    Mais là, mieux vaut, AMA, les encapsuler dans une fonction type factory qui se charge de la construction et de la post-construction.

    Dans 99% des cas je fais tout dans le constructeur, voire je fusionne le résidu init() dans le constructeur principal des classes qu'il m'arrive de refactorer. C'est idiot, mais cela évite les fuites propres à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    T * t = new T();
    t->init(); // peut lever une exception, parce que la clé de connection n'est pas valide...
    return t;
    (oui, les auto_ptr<> sont parfaitement adaptés ici, et correspondent au second patch que j'applique à ce genre de code)
    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...

  6. #6
    r0d
    r0d est actuellement connecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 288
    Billets dans le blog
    2
    Par défaut
    Merci pour vos réponses,

    il semblerait donc que ma fonction Init() soit superflue. Il se trouve cependant que je n'ai pas le choix, elle fait partie du cahier des charges, et du coup, je suis bien obligé de mettre quelque chose dedans...

    Citation Envoyé par Luc Hermitte
    [...] et une nécessité dans les extrêmes rares cas où l'on a besoin de post-construction polymorphique -- si je puis dire.
    je ne comprends pas, pourrais-tu m'expliquer un peu ce que tu veux dire s'il te plait? Qu'est-ce qu'une post-construction polymorphique?

    Citation Envoyé par Luc Hermitte
    Mais là, mieux vaut, AMA, les encapsuler dans une fonction type factory qui se charge de la construction et de la post-construction.
    Ok pour l'encapsulation dans une fonction de type factory. Mais qu'est-ce que AMA?

    Citation Envoyé par Luc Hermitte
    [...] cela évite les fuites propres à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    T * t = new T();
    t->init(); // peut lever une exception, parce que la clé de connection n'est pas valide...
    return t;
    (oui, les auto_ptr<> sont parfaitement adaptés ici, et correspondent au second patch que j'applique à ce genre de code)
    Je ne comprends pas ce que tu veux montrer ici Pourrais-tu me donner quelques explications s'il te plait?

    Citation Envoyé par JolyLoic
    S'il est bien programmé, cette tentative de construction n'aura pas alloué de resosurces sans les libérer.
    Si j'ai bien compris, si on a une construction du type:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    MaClasse::MaClasse(int iValue)
    {
       m_aiMonTableau = new int(iValue);
       try
       {
          m_pMonObjet->Connect(); // connection à une bdd par exemple
       }
     
       catch (CMyConnectionException* pEx)
       {
          pEx->ReportError();
       }
    }
    On risque d'allouer le tableau m_aiMonTableau alors que la classe n'est pas construite? (dans le cas où le connect() renvoie une exception)
    Il faudrait alors rajouter un delete[] m_aiMonTableau; dans le catch. C'est ça?


    Encore merci

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par r0d
    Citation Envoyé par Luc Hermitte
    [...] et une nécessité dans les extrêmes rares cas où l'on a besoin de post-construction polymorphique -- si je puis dire.
    je ne comprends pas, pourrais-tu m'expliquer un peu ce que tu veux dire s'il te plait? Qu'est-ce qu'une post-construction polymorphique?
    Un constructeur ne peut pas être polymorphe, ni appeler une fonction de sa classe de manière polymorphe. Exemple : La classe de base Figue a une fonction draw virtuelle pure. On veut dans le constructeur de chaque figure l'afficher. On ne peut pas directement. On doit alors demander à l'utilisateur d'appeler lui même la fonction draw après la cration. Il s'agit d'une étape post construction, qui est polymorphique.

    Citation Envoyé par r0d
    Citation Envoyé par Luc Hermitte
    Mais là, mieux vaut, AMA, les encapsuler dans une fonction type factory qui se charge de la construction et de la post-construction.
    Ok pour l'encapsulation dans une fonction de type factory. Mais qu'est-ce que AMA?
    AMA = A mon avis.
    Citation Envoyé par r0d
    Citation Envoyé par Luc Hermitte
    [...] cela évite les fuites propres à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    T * t = new T();
    t->init(); // peut lever une exception, parce que la clé de connection n'est pas valide...
    return t;
    (oui, les auto_ptr<> sont parfaitement adaptés ici, et correspondent au second patch que j'applique à ce genre de code)
    Je ne comprends pas ce que tu veux montrer ici Pourrais-tu me donner quelques explications s'il te plait?
    Si init lève une exception, la mémoire (ou autres ressources) allouée pour t n'est jamais libérée.
    Citation Envoyé par r0d
    Citation Envoyé par JolyLoic
    S'il est bien programmé, cette tentative de construction n'aura pas alloué de resosurces sans les libérer.
    Si j'ai bien compris, si on a une construction du type:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    MaClasse::MaClasse(int iValue)
    {
       m_aiMonTableau = new int(iValue);
       try
       {
          m_pMonObjet->Connect(); // connection à une bdd par exemple
       }
     
       catch (CMyConnectionException* pEx)
       {
          pEx->ReportError();
       }
    }
    On risque d'allouer le tableau m_aiMonTableau alors que la classe n'est pas construite? (dans le cas où le connect() renvoie une exception)
    Il faudrait alors rajouter un delete[] m_aiMonTableau; dans le catch. C'est ça?
    Oui et non. Oui le problème est bien celui là. Non, sa résolution ne passe pas par un bloc catch, mais plutôt par du RAII : Par exemple, ici, au lieu d'utiliser un int* pour le tableau, utiliser un vector<int>.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    r0d
    r0d est actuellement connecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 288
    Billets dans le blog
    2
    Par défaut
    Merci pour ces précisions
    Mais j'ai encore une question...
    Citation Envoyé par JolyLoic
    AMA = A mon avis.


    Citation Envoyé par JolyLoic
    Oui et non. Oui le problème est bien celui là. Non, sa résolution ne passe pas par un bloc catch, mais plutôt par du RAII : Par exemple, ici, au lieu d'utiliser un int* pour le tableau, utiliser un vector<int>.
    Qu'est-ce que le RAII? Et comment le vector se débrouille-t-il pour s'auto-effacer en cas de problème dans le constructeur? Utilise-t-il un Observer?

  9. #9
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Le RAII : http://c.developpez.com/faq/cpp/?pag...POINTEURS_raii

    Après avoir lu ça, tu devrais pouvoir répondre tout seul à ta question sur le vector.

  10. #10
    r0d
    r0d est actuellement connecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 288
    Billets dans le blog
    2
    Par défaut
    Ok merci.

    Cet article est vraiment excellent. Il m'a permi de comprendre l'utilité des smart pointers, en plus du RAII que je ne connaissais pas. Un idiome puissant et simple finalement. D'ailleurs, pourquoi n'est-ce pas un design pattern?

  11. #11
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 292
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    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 : 5 292
    Par défaut
    Idiome et design pattern sont deux choses proches arrivées à peu près au même moment (je parle d'histoire) et ayant donc ... des noms différents.
    Aujourdh'ui, on retient (moi du moins) en général qu'un idiome est un petit DP spécialisé pour un langage. Je trouve aussi qu'en C++, on parle plus volontier d'idiomes que de patterns pour des choses comme le RAII, l'enveloppe-lettre, ...

    Quant au RAII, son équivalent dans d'autres langages que je ne citerai pas, est le dispose-pattern ... (Ils s'inscrivent tout deux dans le cadre plus général de la libération déterministe de ressources)
    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...

  12. #12
    r0d
    r0d est actuellement connecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 288
    Billets dans le blog
    2
    Par défaut
    merci à tous, j'ai appris beaucoup grâce à vous. Et bien que j'aie encore tout un tas de questions concernant la conception, je vais clore ce topic et continuer mon investigation tranquillement. Et puis je vais me remettre à l'UML, que je n'ai plus pratiqué depuis l'université

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

Discussions similaires

  1. syntaxe, init membre sans constructeur par défaut
    Par Ghurdyl dans le forum Débuter
    Réponses: 3
    Dernier message: 17/07/2009, 15h33
  2. [VB6]Déclaration d'un Constructeur Spécialisé
    Par TagadaTsoin dans le forum VB 6 et antérieur
    Réponses: 21
    Dernier message: 26/05/2004, 14h09
  3. Capture d'exception dans un constructeur
    Par declencher dans le forum Composants VCL
    Réponses: 8
    Dernier message: 03/02/2004, 12h52
  4. [CR7] Erreur CanNot initalize OLE
    Par elifqaoui dans le forum SAP Crystal Reports
    Réponses: 4
    Dernier message: 17/07/2003, 22h03
  5. pb constructeurs classes dérivant classe abstraite
    Par Cornell dans le forum Langage
    Réponses: 2
    Dernier message: 10/02/2003, 19h02

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