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 :

Wrapper std::vector ou pas ?


Sujet :

C++

  1. #1
    Membre confirm�
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    96
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 96
    Par d�faut Wrapper std::vector ou pas ?
    Bonsoir,

    Je suis r�guli�rement confront� � un choix et je n'arrive pas � me d�cider.

    Si une objet A comporte un std::vector, et qu'un autre objet B cherche � acc�der � tous les �l�ments de ce vector :
    - Il vaut mieux �crire les accesseurs de A utilis�s par B qui permettent cette op�ration. Fastidieux mais opaque.

    O�

    - Il vaut mieux retourner std::vector<MonType>&. Simple mais transparent.

  2. #2
    Expert �minent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activit� : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par d�faut
    Salut,

    Commence d'abord par te poser la question de savoir s'il est coh�rent que ton objet de type C puisse acc�der aux �l�ments (de type B) contenus dans le vecteur du type A...

    En effet, la loi demeter nous incite � veiller � ce que, si un objet de type A contient un objet de type B, un objet de type C connaissant l'objet de type A ne devrait pas pouvoir acc�der, au d�part de l'objet de type A, � l'objet de type B, dont C ne devrait d'ailleurs avoir aucune connaissance.

    Le corolaire de cette loi est que la r�ponse d�pendra principalement de la responsabilit� que tu envisage de donner pour A.

    Dans certains cas, il sera plutot opportun de fournir des fonctions membres � A qui permettent "simplement" d'effectuer certains traitement sur tout ou partie du contenu de la collection de B sans pour autant exposer le fait que A manipule des B, les B n'�tant alors consid�r� que comme... des donn�es permettant � A de fournir les services que l'on attend de sa part

    Dans d'autres, la classe A se "substitue" � la collection (au vector) et sa responsabilit� est alors de g�rer les objets de type B.

    L'approche la plus mal�able est alors de se dire que le vector n'est en r�alit� qu'un d�tail d'impl�mentation, qui pourrait parfaitement �tre remplac� par n'importe quel autre type de conteneur pr�sentant une interface identique (list, set ou autre), mais que l'utilisateur de A n'a strictement aucun besoin de savoir si les diff�rents objets sont bel et bien plac�s dans un vector, ou s'ils sont en r�alit� plac�s dans une list

    Dans ce cas l�, quelques typedef de visibilit� bien choisie et quelques fonctions utiles repr�sentent, � mon sens, la meilleur alternative.

    Il peut, en effet, paraitre fastidieux de cr�er les typedefs et les fonctions membres, mais le temps "perdu" � le faire sera tr�s largement r�cup�r� en terme de facilit� et de s�curisation d'utilisation, voire, en terme de d�cision diff�rente ult�rieure.

    Ainsi, il faut comprendre que si tu renvoie une r�f�rence sur le conteneur (quel qu'il soit) non constante au d�part d'une fonction membre non constante de ta classe, tu ouvre la porte � une modification incontr�l�e et incontr�lable du contenu de celui-ci, sans compter le fait que tu rend bien plus compliqu�e la d�cision �ventuelle de changer le type de la collection parce que certains bench en auraient d�montr� l'opportunit�

    En un mot, et bien que cela puisse paraitre paradoxal, je dirais presque que ton but doit �tre de te compliquer la vie afin de faciliter celle de ceux qui utiliseront ton travail

    Pour moi, la meilleure mani�re de t'y prendre, s'il est acquis que A se substitue r�ellement � une collection, serait donc de partir d'une classe A ressemblant � quelque chose comme
    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
    class A
    {
        /* ce typedef est privé par défaut, car à usage interne uniquement */
        typedef std::vector<UnType> vector;
        public:
            /* il faudra surement l'itérateur constant */
            typedef vector::const_iterator const_iterator;
            /* et  * peut être * l'itérateur non constant */
            typedef vector::iterator iterator;
            /* on rajoute les fonctions qui vont bien */
            A(){}
            template <typename iterator>
            A(iterator b, iterator e):tab(b,e){}
            const_iterator begin() const{return tab.begin();}
            const_iterator end() const{return tab.end();}
            const_iterator find(/* paramètres */) const; // si elle est utile
            size_t size() const{return tab.size();}
            void add(UnType);
            /* toutes les autres fonctions utiles (éventuellement non constantes) 
             */
        private:
            vector tab;
    }
    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

  3. #3
    Membre confirm�
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    96
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 96
    Par d�faut
    Merci

    J'ai rien compris � la loi Demeter.
    �a signifie qu'une m�thode d'un objet A ne doit pas acc�der � une collection d'objet dans un autre objet B qui se trouve dans A ?
    EDIT : Google est mon amis, Oui la loi demeter c'est �a...

    Mais comme tu dis, masquer le fait qu'il s'agit d'un std::vector est une chose importante.

  4. #4
    Membre Expert

    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 49
    Localisation : France, Bouches du Rh�ne (Provence Alpes C�te d'Azur)

    Informations professionnelles :
    Activit� : D�veloppeur informatique
    Secteur : High Tech - Op�rateur de t�l�communications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par d�faut
    Citation Envoy� par Agoudard Voir le message
    Mais comme tu dis, masquer le fait qu'il s'agit d'un std::vector est une chose importante.
    C'est m�me certainement le point le plus important, car ainsi tu masque ton impl�mentation, for�ant l'utilisateur � utiliser ton interface (paradigme program to interface). Tu t'assure ainsi d'un meilleur contr�le de l'invariant de la classe, puisque l'�tat de ta classe ne peut �tre modifi� sans passer par le chemin que tu imposes.

    Bien �videmment, �a n�cessite de pr�voir une interface bien pens�e, ce qui te force � r�fl�chir aux objectifs que tu t'es fix� et � la place de cette classe dans ton plan global.

    Bref, bien programmer, �a force � bien concevoir
    [FAQ des forums][FAQ D�veloppement 2D, 3D et Jeux][Si vous ne savez pas ou vous en �tes...]
    Essayez d'�crire clairement (c'est � dire avec des mots fran�ais complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Caf�. C'est d�pass� tout �a.
    Et si vous �tes sages, vous aurez peut �tre vous aussi la chance de passer � la t�l�. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  5. #5
    Membre �clair�
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Par d�faut
    Je reste dubitatif (je suis comme le PO, je me pose cette question depuis un moment d�j�).

    @koala01 : si la classe A dispose en interne d'un autre vecteur, l'interface peut vite devenir compliqu�e

    Personnellement, j'en suis arriv� � retourner une r�f�rence constante sur le vecteur interne avec une m�thode add. J'utilise �norm�ment du concept de range, donc j'ai pas vraiment besoin des begin / end

    Mon design m'am�ne souvent dans ce cas � consid�rer que A doit g�rer l'aspect collection (je restreint donc la possibilit� d'ajouter des �l�ments) par contre A ne doit pas contr�ler le contenu (mes vecteurs sont alors des vecteurs de pointeurs ce qui permet lors du renvoi de la r�f�rence constante sur le vecteur d'interdire l'ajout / suppression d'�l�ments mais autorise l'appel de m�thodes non constantes sur mes objets)

    ex:
    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
     
    #define foreach BOOST_FOREACH
     
    struct A
    {
      typedef std::vector<std::shared_ptr<MonType>> lstTypes;
     
      void add(std::shared_ptr<MonType>& elt);
      //il m'arrive aussi d'utiliser des méthodes add avec les paramètres nécessaires à la construction d'un MonType
     
      lstTypes const& mes_types() const;
     
    private:
       lstTypes mes_types_m;
    };
     
    int main()
    {
      A a;
      using namespace boost::adaptors;
      foreach(UnType& t, a.mes_types() | indirected)
      {
        //faire un truc avec t mais pas forcement de méthodes constantes
      }
    }

  6. #6
    Expert �minent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activit� : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par d�faut
    Citation Envoy� par Agoudard Voir le message
    Merci

    J'ai rien compris � la loi Demeter.
    �a signifie qu'une m�thode d'un objet A ne doit pas acc�der � une collection d'objet dans un autre objet B qui se trouve dans A ?
    EDIT : Google est mon amis, Oui la loi demeter c'est �a...
    Un petit exemple, ca vaudra sans doute mieux qu'un grand discours :
    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
    class B
    {
        public:
            void doSomthing()/* const */ {/*...*/}
    };
    class A
    {
        private /* ou protected */:
        B b;
    };
    class C
    {
        public:
            void foo(A /* const & */ a);
    };
    Si tu veux invoquer la fonction doSomething du membre b de type B qui se trouve dans la classe A, tu as la mauvaise m�thode qui consiste � offrir un accesseur sur b:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class A
    {
       public:
           B /* const & */ getB() /* const{return b;}
           /* comme plus haut */
    };
    void C::foo(A /* const & a)
    {
        a.getB().doSomething();
    }
    En effet, bien que *relativement simple*, cette solution oblige le type C � connaitre le type B, alors qu'il doit d�j� connaitre le type A.


    Et tu as la bonne m�thode qui consiste � se dire que la classe A connait d�j� la classe B et sait donc qu'il existe la fonction B::doSomething.

    Il n'y a donc aucune raison � forcer C � connaitre la classe B: Par contre, on peut estimer que l'invocation de b::doSomething fait partie des services rendus (�ventuellement � l'int�rieur d'une logique plus complexe) par la classe A.

    De cette mani�re, celui qui utilise la classe A (C dans mon exemple) ne doit connaitre que la classe A, et rien d'autre :
    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
    class A
    {
        public:
            void anyService() /* const */
            {
                /* éventuellement quelque chose avant */
                b.doSomething();
            }
        private:
            B b;
    };
    void C::foo(A /* const & */ a)
    {
        a.anyService();
    }
    Citation Envoy� par CedricMocquillon Voir le message
    Je reste dubitatif (je suis comme le PO, je me pose cette question depuis un moment d�j�).

    @koala01 : si la classe A dispose en interne d'un autre vecteur, l'interface peut vite devenir compliqu�e
    Elle ne devrait pas...

    Il y a en effet un autre principe qu'il s'agit de garder en t�te: il est connu sous le terme de SRP (Single Responability Principle, ou principe de la responsabilit� unique, si tu pr�f�re en francais )

    C'est ce fameux principe qui dit, entre autre, que si une fonction fait plus d'une chose, c'est sans doute qu'elle en fait trop.

    Mais ce n'est pas seulement vrai pour les fonctions, ce l'est aussi pour les classes et les structures

    M�me en g�n�ralisant au mieux la responsabilit� que l'on souhaite donner � une classe qui manipule une collection d'objets, on reste dans l'ordre de "sa resposabilit� est de permettre la gestion des diff�rents objets".

    Mais, comme Emmanuel l'a fait remarquer, l'id�al reste toujours de veiller � ne
    pas exposer le type de collection qui est manipul� par la classe
    Personnellement, j'en suis arriv� � retourner une r�f�rence constante sur le vecteur interne avec une m�thode add.
    C'est un tord
    J'utilise �norm�ment du concept de range, donc j'ai pas vraiment besoin des begin / end
    Et pourtant, si tu pr�sente simplement des fonctions qui renvoient un it�rateur:
    1. begin permet d'obtenir le premier �l�ment sans se poser de question
    2. end permet de s'assurer que l'it�rateur renvoy� est valide
    3. il manque "juste" une fonction find qui te permette de d�terminer les deux extr�mes de ton range (outre, bien sur, les fonctions permettant de rajouter des �l�ments


    Mon design m'am�ne souvent dans ce cas � consid�rer que A doit g�rer l'aspect collection (je restreint donc la possibilit� d'ajouter des �l�ments) par contre A ne doit pas contr�ler le contenu (mes vecteurs sont alors des vecteurs de pointeurs ce qui permet lors du renvoi de la r�f�rence constante sur le vecteur d'interdire l'ajout / suppression d'�l�ments mais autorise l'appel de m�thodes non constantes sur mes objets)
    Tu peux parfaitement renvoyer des it�rateurs non constants, s'il apparait que la modification de l'�l�ment n'occasionne pas la modification de l'objet g�rant la collection... mais ce n'est pas forc�ment le cas
    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
     
    #define foreach BOOST_FOREACH
     
    struct A
    {
      typedef std::vector<std::shared_ptr<MonType>> lstTypes;
     
      void add(std::shared_ptr<MonType>& elt);
      //il m'arrive aussi d'utiliser des méthodes add avec les paramètres nécessaires à la construction d'un MonType
     
      lstTypes const& mes_types() const;
     
    private:
       lstTypes mes_types_m;
    };
     
    int main()
    {
      A a;
      using namespace boost::adaptors;
      foreach(UnType& t, a.mes_types() | indirected)
      {
        //faire un truc avec t mais pas forcement de méthodes constantes
      }
    }
    L�, tu n'utilise pas vraiment un range: tu invoque de mani�re syst�matique une s�rie de fonctions sur l'ensemble du contenu

    Par contre, avec begin et end, tu peux *r�ellement* travailler sur des ranges, et ce sera encore plus le cas avec la nouvelle norme qui autorise
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    std::for_each(iter_begin, iter_end, functor);
    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

  7. #7
    Membre �clair�
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Par d�faut
    Je suis d'accord avec ta position et celle d'Emmanuel, je me fait ici un peu l'avocat du diable :-)

    J'aurai du dans mon exemple remplacer le renvoi d'une r�f�rence constante sur le vecteur par un sub_range de boost qui correspond plus � mon intention initiale : renvoyer une "paire d'it�rateurs" ayant l'interface d'une collection.

    Ce que je voulais illustrer c'est que pour moi le code "client" de la classe A ne doit pas faire (trop) d'hypoth�ses sur la repr�sentation interne des objets de A (notamment au niveau de la liste (ici pris au sens large du terme) des MonType). Utiliser un BOOST_FOREACH ou encore un boost::for_each (de boost/range/algorithm) ou encore BOOST_AUTO ou encore auto (de C++0x) permet de "r�cup�rer" lstTypes et de travailler dessus sans "trop" faire d'hypoth�ses sur le type de collection utilis� en interne.

    Je te conc�de que c'est �galement le cas avec les it�rateurs pour autant, on a toujours des limites au fait de cacher la repr�sentation interne, avec un it�rateur (ou un sub_range): si on change la repr�sentation interne de la collection des MonType d'un vector � une map, le code client sera impact� (on ne peut plus simplement d�r�f�rencer l'it�rateur pour acc�der � l'�l�ment, on est oblig� de faire un truc style it->second).

    On peut encore dans ce cas, changer le type des it�rateurs expos�s (je pense notamment � iterator transform) pour masquer ce changement, il n'emp�che que modifier le mode de gestion des objets (passer d'un vector<MonType> � un vector<shared_ptr<MonType>>) n'est pas non plus trivial � "masquer" pour le code client.

    �a me rappelle un bouquin (de Meyer il me semble, genre Effective STL) qui indiquait qu'il y a des limites � l'interchangeabilit� des types de conteneurs et que ce n'est pas non plus ce qu'il fallait forc�ment chercher dans nos codes.

    Au final, je suis d'accord avec le SRP et Demeter c'est juste que c'est parfois un brin "plus simple" de faire une petite entorse � la r�gle notamment quand on a un contr�le total sur le code "client". Apr�s je ne tiendrais pas le m�me discours pour le d�veloppement d'une biblioth�que "g�n�rique" � plus large diffusion.

    Enfin dernier point, malgr� le SRP, il m'arrive d'avoir � g�rer au sein d'une m�me classe, plusieurs collection (c'est plut�t l'exception mais �a m'arrive). Prenons l'exemple d'une ferme avec ses animaux, j'aurais tendance � �crire un code proche de:
    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
     
    class ferme
    {
    public:
     
      void add(volaille);
      void add(canard);
      void add(poulet);
      void add(cochon);
     
      lstAnimaux animaux() const;
      lstVolailles volailles() const;
      lstCanards canards() const;
      lstPoulets poulets() const;
      lstCochons cochons() const;
     
    private:
      std::vector<animal*> animaux_m;
      std::vector<volaille*> volailles_m;
      std::vector<canard*> canards_m;
      std::vector<poulet*> poulets_m;
      std::vector<cochon*> cochons_m;
    };
    Avec volaille et cochon h�ritant d'animal et canard et poulet h�ritant de volaille.

    Personnellement, je ne consid�re pas (je fait peut �tre une erreur ici) que Demeter est "viol�", un code client qui compte manipuler une ferme sans conna�tre quels sont les animaux pr�sents ne me para�t pas r�aliste.

  8. #8
    Membre Expert

    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 49
    Localisation : France, Bouches du Rh�ne (Provence Alpes C�te d'Azur)

    Informations professionnelles :
    Activit� : D�veloppeur informatique
    Secteur : High Tech - Op�rateur de t�l�communications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par d�faut
    Citation Envoy� par CedricMocquillon Voir le message
    Je reste dubitatif (je suis comme le PO, je me pose cette question depuis un moment d�j�).

    @koala01 : si la classe A dispose en interne d'un autre vecteur, l'interface peut vite devenir compliqu�e
    Si la classe en interne poss�de un autre vecteur, alors son r�le n'est clairement pas celui d'un conteneur - du coup, son interface se doit de le refl�ter. Elle ne devient donc pas n�cessairement plus compliqu�e.

    Citation Envoy� par CedricMocquillon Voir le message
    Personnellement, j'en suis arriv� � retourner une r�f�rence constante sur le vecteur interne avec une m�thode add. J'utilise �norm�ment du concept de range, donc j'ai pas vraiment besoin des begin / end

    Mon design m'am�ne souvent dans ce cas � consid�rer que A doit g�rer l'aspect collection (je restreint donc la possibilit� d'ajouter des �l�ments) par contre A ne doit pas contr�ler le contenu (mes vecteurs sont alors des vecteurs de pointeurs ce qui permet lors du renvoi de la r�f�rence constante sur le vecteur d'interdire l'ajout / suppression d'�l�ments mais autorise l'appel de m�thodes non constantes sur mes objets)
    L'int�r�t d'encapsuler un vecteur, c'est de permettre d'effectuer des traitements plus sp�cialis�s sur ce vecteur. Dans on exemple, il eut �t� plus simple de proposer un m�thode foreach() dans ta classe (prenant par exemple un foncteur en param�tre) plutot que d'exposer la collection interne.

    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
     
    struct A // la même que ta classe, plus : 
    {
    public:
      template <class Callable> void foreach(Callable callable)
      {
        std::for_each(mes_types_m.begin(), mes_types_m.end(), callable);
      }
      typedef lstTypes::value_type type;
    };
     
    int main()
    {
      A a;
     
      // je mets une lambda, histoire de simplifier le code ; on peut passer
      // n'importe quel callable, que ce soit un foncteur, un boost.function,
      // etc.
      a.foreach([](A::type& v){ v.bar(); });
    }
    [FAQ des forums][FAQ D�veloppement 2D, 3D et Jeux][Si vous ne savez pas ou vous en �tes...]
    Essayez d'�crire clairement (c'est � dire avec des mots fran�ais complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Caf�. C'est d�pass� tout �a.
    Et si vous �tes sages, vous aurez peut �tre vous aussi la chance de passer � la t�l�. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  9. #9
    Expert �minent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activit� : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par d�faut
    De plus, si "volaille","cochon","canard" et "poulet" h�ritent, de mani�re directe ou inidirecte de "animal", on peut clairement estimer que les tableaux correspondant ne sont l� que pour te permettre de garder une certaine s�paration des diff�rents �l�ments si, d'aventure, tu as besoin d'un type d'animal donn�, de mani�re � ne pas te trouver face � une situation dans laquelle tu devrais commencer � v�rifier le type r�el de tous les animaux lorsque tu ne voudrais travailler que sur un type particulier.


    Nous en revenons donc bel et bien dans le cas o� les diff�rents tableaux (hormis le tableau d'animaux) ne sont l� que... pour permettre � la classe de rendre les services que l'on attend d'elle. Et cela ne signifie pas forc�ment renvoyer ces tableaux
    Je te conc�de que c'est �galement le cas avec les it�rateurs pour autant, on a toujours des limites au fait de cacher la repr�sentation interne, avec un it�rateur (ou un sub_range): si on change la repr�sentation interne de la collection des MonType d'un vector � une map, le code client sera impact� (on ne peut plus simplement d�r�f�rencer l'it�rateur pour acc�der � l'�l�ment, on est oblig� de faire un truc style it->second).
    Tout � fait, il y a des limites...

    Mais elles sont malgr� tout moins restreintes d�s que tu veilles � travailler avec des it�rateurs et � garder les garder compatibles

    Sans compter le fait que, si tu en viens � remplacer un std::vector (ou tout autre collection pr�sentant des it�rateurs compatibles) par une std::map, c'est sans doute que tu red�finis en profondeur la responsabilit� de ta classe et qu'elle n�cessitera de toutes mani�res un remaniement en profondeur
    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
    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 : 51
    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 CedricMocquillon Voir le message
    �a me rappelle un bouquin (de Meyer il me semble, genre Effective STL) qui indiquait qu'il y a des limites � l'interchangeabilit� des types de conteneurs et que ce n'est pas non plus ce qu'il fallait forc�ment chercher dans nos codes.
    Il en parle dedans, en effet. Le cas o� l'interface est diff�rente n'est peut-�tre pas le pire. Il y a aussi le cas o� tout compile, tout marche, on a simplement introduit un algorithme d'une complexit� absurde.

    Citation Envoy� par CedricMocquillon Voir le message
    Enfin dernier point, malgr� le SRP, il m'arrive d'avoir � g�rer au sein d'une m�me classe, plusieurs collection (c'est plut�t l'exception mais �a m'arrive).
    �a m'arrive aussi. Par exemple, dans une classe de graphes, avoir dans une classe N�ud un conteneur pour les n�uds pr�c�dents, et un pour les n�uds suivants n'est pas absurde.


    Citation Envoy� par Emmanuel Deloget Voir le message
    L'int�r�t d'encapsuler un vecteur, c'est de permettre d'effectuer des traitements plus sp�cialis�s sur ce vecteur. Dans on exemple, il eut �t� plus simple de proposer un m�thode foreach() dans ta classe (prenant par exemple un foncteur en param�tre) plutot que d'exposer la collection interne.

    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
     
    struct A // la même que ta classe, plus : 
    {
    public:
      template <class Callable> void foreach(Callable callable)
      {
        std::for_each(mes_types_m.begin(), mes_types_m.end(), callable);
      }
      typedef lstTypes::value_type type;
    };
     
    int main()
    {
      A a;
     
      // je mets une lambda, histoire de simplifier le code ; on peut passer
      // n'importe quel callable, que ce soit un foncteur, un boost.function,
      // etc.
      a.foreach([](A::type& v){ v.bar(); });
    }
    Bof... On permet de faire un for_each, mais avec une syntaxe assez lourde, et on emp�che de faire plein d'autres choses qui seraient valides aussi. Ne serait-ce qu'ex�cuter le m�me for-each en parall�le (ce qui est un choix que doit effectuer le client de la classe, et non son concepteur, car lui seul sait si les traitements sont compatibles avec le parall�lisme.

    Et m�me si on voulait ne permettre qu'un for-each, je pr�f�re la syntaxe sans lambdas ni liste de capture :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    for(auto node : A.previousNodes())
    {
      // Faire quelquechose
    }
    En fait, je pense qu'il y a des classes pour lesquelles dire qu'elle est compos� d'une collection de sous objets fait partie de l'interface, qu'on ne sait pas a priori comment ces objets vont �tre manipul�s, et qu'on n'a pas envie de brider l'utilisateur et dans ce cas, autant l'exposer (peut-�tre juste sous forme de range, si c'est une exposition en lecture seule, sinon directement le conteneur).

    Et il y a des classes pour lesquelles le fait de g�rer une collection est un d�tail d'impl�mentation, et l�, d'accord pour ne pas l'exposer et fournir seulement des fonctionnalit�s de plus haut niveau (et je ne consid�re pas vraiment le fait d'iterer comme de haut niveau).

    Un exemple qui pour moi entre clairement dans la premi�re cat�gorie, c'est encore une fois ma classe de N�ud dans un graphe. Un exemple de la seconde cat�gorie serait par exemple une classe g�rant des pr�ts pour une biblioth�que, qui aurait des fonctions EnvoyerLettreDeRappel, AjouterUnLivre...

    Il n'est pas innocent que l'un de mes exemples soit une classe technique, et l'autre une classe m�tier.
    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.

+ R�pondre � la discussion
Cette discussion est r�solue.

Discussions similaires

  1. std::vector semble ne pas utiliser std::move, pourquoi ?
    Par n0-sheep dans le forum SL & STL
    R�ponses: 7
    Dernier message: 15/03/2014, 01h25
  2. R�ponses: 10
    Dernier message: 30/06/2008, 19h59
  3. vertex array et std::vector marche pas, help!
    Par filoo dans le forum OpenGL
    R�ponses: 14
    Dernier message: 07/07/2007, 13h00
  4. std ::vector [erreur que je ne comprend pas]
    Par aaronw dans le forum SL & STL
    R�ponses: 8
    Dernier message: 05/03/2006, 21h00
  5. Sauvegarde std::vector dans un .ini
    Par mick74 dans le forum MFC
    R�ponses: 2
    Dernier message: 12/05/2004, 13h30

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