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 :

Possibilité d'objet partagé


Sujet :

C++

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2012
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 2
    Points : 2
    Points
    2
    Par défaut Possibilité d'objet partagé
    Bonjour,

    j'aimerais savoir si il est possible de créer des objets que l'on pourrais partager sur plusieurs classe (un peu comme une union en C).

    Pour vous expliquer mon problème est que mon main() contient un élément topology (initialisé et remplit) auquel j'aimerais avoir accès dans presque toutes les fonctions du programme.

    La définition de topology ce fait comme suit:
    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
    class Topology 
    {
    	public:
    		virtual void init(uint ports, uint vcs, uint credits, uint buffer_size, uint no_nodes, uint grid_size, uint links) = 0;
    		virtual void setup(void) = 0;
    		virtual void connect_interface_processor(void) = 0;
    		virtual void connect_interface_routers(void) = 0;
    		virtual void connect_routers(void) = 0;
    		virtual string print_stats(void) = 0;
    		Topology() {}
    		virtual ~Topology() {}
     
    		unsigned long long int max_sim_time;
    		map< uint , uint > east_links;
    		map< uint , uint > west_links;
    		map< uint , uint > north_links;
    		map< uint , uint > south_links;
    		vector <Router*> routers;
    		vector <Interface*> interfaces;
    		vector <Processor*> processors;
    		vector <GenericLink*> link_a;
    		vector <GenericLink*> link_b;
     
    }
    ;
    Je pourrais le mettre en paramètre de chacune des fonctions mais cela serais trop compliqué et entraînerais sûrement des inclusions cyclique.

    Un petit point à précisé, je débute en POO donc désolé si cette question vous paraît trivial.

    Merci d'avance.

  2. #2
    Invité
    Invité(e)
    Par défaut
    salut,

    regarde du côté du singleton.

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    le plus simple c'est un simple singleton.
    Tu vires le constructeur qui passe protected/private et tu récupères l'instance via une méthode statique
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Topology {
     private: Topology() {}
    public: static Topology& Get() {
      static Topology sing;
      return sing;
      }
    };
     
    Topology& myTopology = Topology::Get();
    Sinon de manière générale, il faut juste un pointeur/référence à partager entre ceux qui ont besoin de connaître l'objet/instance en question.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Si, déjà, tu en es à devoir utiliser ta classe "partout", j'aurais vraiment tendance à dire qu'il y a, dés le départ, un problème de conception.

    Sans rien savoir de ton projet, je ne suis pas loin de penser qu'il y a au moins l'un des principes repris ci-dessous (et, qui sait, peut etre même plusieurs ) qu'il serait bon de prendre en compte:
    1. SRP ( Single Responsability Principle ) : le principe de la responsabilité unique >> si une classe ou une fonction prend plus d'une responsabilité, c'est sans doute qu'elle en a trop
    2. Loi Demeter >> si une classe A utilise la classe B et que la classe B utilise elle-même la classe C, A ne devrait pas avoir besoin de connaitre la classe C pour pouvoir utiliser la classe B
    3. DIP ( Dependnecies Inversion Principle ) : Principe de l'Inversion des Dépendances >> les parties "de haut niveau" ne devraient pas dépendre des détails d'implémentations
    4. ISP ( Interface Segregation Principle ) : Principe de la Ségrégation des Interfaces >> les classes abstraites ne devraient pas dépendre de classes concrètes : ce sont les classes concrètes qui devraient dépendre des classes abstraites
    Ce n'est sans doute pas la cause de ton malheur (c'en serait plutot une conséquence ), mais je ne serais pas surpris que, si tu continue dans cette voie, tu finisses tot ou tard par éprouver de très grandes difficultés à respecter un dernier principe: OCP (Open / Close Principle) : Le principe ouvert / fermé >> ton code doit rester ouvert aux évolutions, mais etre fermé aux modifications (tu ne devrais pas avoir à modifier l'existant pour ajouter une fonctionnalité)

    Vraiment, je ne saurais trop t'inciter à essayer de réfléchir à la manière d'éviter d'avoir à te trimballer une instance unique de Topology, d'autant plus que tu sembles décidé à permettre qu'elle serve de base à un héritage public comme en atteste la présence de fonction virtuelles pure...

    La notion de singleton se marie en effet relativement mal avec celle d'héritage public quand la classe de base n'est pas une classe template
    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

  5. #5
    Invité
    Invité(e)
    Par défaut
    Vraiment, je ne saurais trop t'inciter à essayer de réfléchir à la manière d'éviter d'avoir à te trimballer une instance unique de Topology, d'autant plus que tu sembles décidé à permettre qu'elle serve de base à un héritage public comme en atteste la présence de fonction virtuelles pure...
    ben en supposant que Topology ca soit une entité, qui n'a aucun sens d'être copiée. Tu vas pas la copier dans toutes les classes.
    Par ailleurs la gueule que ca a avec un nom pareil, c'est plus une datastructure, donc vaut mieux éviter les dupplications.
    Je suis pas proneur du Singleton, mais pour le coup, je vois pas trop d'alternatives.

  6. #6
    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 : 49
    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
    Points : 2 605
    Points
    2 605
    Par défaut
    Bonjour.

    La classe Topology est une classe virtuelle pure... Quelque chose m'échappe.

    Citation Envoyé par Xilyos Voir le message
    mon main() contient un élément topology (initialisé et remplit)
    C'est quoi un élément topology (un objet qui dérive de topology ?). Merci de préciser.

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par galerien69 Voir le message
    ben en supposant que Topology ca soit une entité, qui n'a aucun sens d'être copiée. Tu vas pas la copier dans toutes les classes.
    Par ailleurs la gueule que ca a avec un nom pareil, c'est plus une datastructure, donc vaut mieux éviter les dupplications.
    Je suis pas proneur du Singleton, mais pour le coup, je vois pas trop d'alternatives.
    Si ce n'est que...

    Si tu regardes bien, tu te rendras compte que Topology est remplie de fonctions virtuelles pures, ce qui fait que l'on ne peut pas instancier un objet de type Topology.

    Il faut donc faire hériter une autre classe qui définira les fonctions virtuelles pures.

    En soit, ce n'est pas très grave (pour autant que l'on travailles alors avec un pointeur sur Topology, quitte à renvoyer "ce qui est pointé" sous forme de référence), mais, le but du singleton est... de ne permettre à une seule instance de la classe d'exister.

    Quel que soit le nombre de classes que l'on fera dériver de Topology (et le simple fait que l'on ouvre la porte à l'héritage, implique que n'importe qui peut décider à sa guise de faire hériter une de ses classes de Topology), on ne pourra donc en tout état de cause jamais avoir qu'un et un seul objet de type (dérivant de) Topology à un instant T.

    Ce n'est pas forcément faux, mais tu avoueras que cela place quand même une très sérieuse restriction à l'utilisation des classes dérivées

    En outre, au vu des noms des fonctions, je subodore réellement qu'il y a au moins trois responsabilités distinctes à cette interface, ce qui en fait, au minimum deux de trop

    Personnellement, je ne suis pas loin de me dire que je préférerais sans doute cacher purement et simplement l'existence de l'instance de Topology (en déclarant une variable globale directement dans le *.cpp qui contient l'implémentation de quelques fonctions qui l'utilisent) et en créant des fonctions libres qui invoqueraient directement la fonction adéquate au départ de cette variable "globale".

    Cela pourait donner quelque chose comme
    TopoFunc.h;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void connect_interface_processor();
    void connect_interface_routers();
    void connect_routers();
    string print_stats();
    TopoFunc.cpp
    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
    /* oui!, je sais, cela peut paraitre bizare, mais, comme on n'utilisera Topology qu'ici,
     * autant éviter à l'utilisateur de savoir que ca existe :D
     */
    class Topology 
    {
        public: 
            /*... */   
    } topo;
    void connect_interface_processor()
    {
        topo.connect_interface_processor();
    }
    void connect_interface_routers()
    {
        topo.connect_interface_routers();
    }
    void connect_routers()
    {
        /* dans la meme veine */
    }
    string print_stats(void)
    {
        /* dans la meme veine */
    }
    Au moins, de cette manière, l'instance de Topography sera un minimum protégée, ne pouvant être utilisée que... par les fonctions qui sont définies dans le fichier *.cpp.

    Ce ne sera toujours pas l'idéal, mais cela permettra, au moins, d'éviter quelques cas susceptibles de créer des effets de bord indésirables

    Pour terminer sur quelques détails troublants:
    1. La fonction init devrait bien plus surement être remplacée par le constructeur
    2. La fonction setup peut éventuellement rester, si tant est qu'elle permette de remettre l'objet "en état" après un problème
    3. Les fonction connect_XXX risquent fortement d'avoir besoin de paramètres
    4. Il est généralement utile de travailler "en mirroir" : si une fonction permet de faire quelque chose, il est souvent de bon ton de fournir une fonction qui permet de le défaire (surtout si la fonction s'appelle "connect" )
    5. Il est rarement bon qu'une classe d'interface (car c'est bel et bien de cela qu'il s'agit, étant donné que toutes les fonctions sont virtuelles pures) contienne des données, surtout si se sont des collections de pointeurs sur des classes qui semblent très clairement destinées à être dérivées... Il est généralement préférable de laisser ce soin aux classes qui implémentent l'interface

    Citation Envoyé par moldavi Voir le message
    Bonjour.

    La classe Topology est une classe virtuelle pure...
    En fait, mais bon, ce n'est qu'un détail, on parle de classe abstraite, c'est à dire une classe ne pouvant pas être instanciée en tant que telle du fait de la présence d'au moins une fonction virtuelle pure (il n'y a que les fonctions qui puissent être virtuelles et que les fonctions virtuelles qui puissent être pures )
    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

  8. #8
    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 : 49
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par galerien69 Voir le message
    ben en supposant que Topology ca soit une entité, qui n'a aucun sens d'être copiée. Tu vas pas la copier dans toutes les classes.
    Par ailleurs la gueule que ca a avec un nom pareil, c'est plus une datastructure, donc vaut mieux éviter les dupplications.
    Je suis pas proneur du Singleton, mais pour le coup, je vois pas trop d'alternatives.
    Que Topology soit une classe de type entité et non pas valeur, pourquoi pas. Je n'ai pas compris son rôle, donc je ne serai pas définitif sur le sujet, mais ça ne me semble pas délirant, et en tout cas la manière dont elle est mise en place va bien dans ce sens.

    Qu'une classe de type entité ne supporte pas la copie, c'est très bien.

    De là à dire qu'elle devrait être singleton, il y a un énorme pas à franchir. Un singleton n'est pas seulement une classe ne supportant pas la copie, mais une classe dont il ne peut exister qu'une seule instance, ce qui est tout de même très différent (un compte bancaire est non copiable, mais une banque a intérêt à gérer plusieurs comptes pour être rentable).

    Un effet annexe de l’existence d'une seule instance est que du coup il est possible de mettre en place un mécanisme pour accéder à cette instance unique depuis n'importe où dans le programme. Et c'est cet accès depuis n'importe où sans passer l'instance en argument, plus que l'instance unique, qui a fait le "succès" du singleton, mais qui est aussi son principal problème.

    Déjà, on peut noter qu'il existe d'autres mécanismes que le singleton si on veut juste donner accès à une instance depuis n'importe où. Par exemple la variable globale (c'est ce qu'on utilise avec std::cout). Ou encore une fonction retournant une variable statique (exemple : std::locale::classic).

    L'avantage de ces alternatives est qu'elles permettent quand même à d'autres instances de la classe d'exister. Dans le cas qui nous intéresse, ça ne me semble pas absurde a priori de vouloir dans un même programme faire des calculs avec deux topologies différentes, et en comparer le résultat.

    L'inconvénient de ces alternatives, c'est qu'à la base, la notion même d'avoir un objet accessible depuis n'importe où sans être passé en argument, bien que pratique et séduisante au premier abord, pose problème. Elle pose problème parce que du coup, on a un état caché dans toutes les fonctions du programme. Qu'on ne peut plus faire aucun test unitaire d'aucune fonction en regardant uniquement ses arguments et ses valeurs de retour, mais qu'il faut tenir compte de cet état caché. Que l'on ne peut plus raisonner sur le code sans devoir se dire que potentiellement le résultat de toute fonction peut dépendre de cet état caché. Et pour peu que cet objet accessible de partout soit modifiable, on ne peut plus exécuter aucun code en parallèle à cause de cet état caché, on sait plus si on peut écrire du code réentrant, des callbacks... à cause de cet état caché. Cette notion d'état caché utilisé en interne d'une fonction sans faire partie de l'interface est par exemple au cœur de fonctions comme strtok. Et c'est la raison pour laquelle strtok est complexe, génératrice d'erreur et globalement considérée comme à éviter.

    Alors que faire ? Le plus simple est probablement de passer la topologie en paramètre de chaque fonction devant l'utiliser (quand je dis passer en paramètre, bien entendu, pas par copie. Cette classe reste non copiable, et est pssée par référence, de préférence constante). Du coup, on sait quelle fonction l'utilise, quelle fonction ne l'utilise pas. On peut faire simultanément des calculs avec des topologies différentes. On sait que si une fonction n'a pas cet argument, elle n'utilise pas la topologie, et que donc on n'a pas besoin de la tester dans différents cas de topologie, voir si elle marche encore.

    Une alternative qui peut être pratique dans certains cas, si les fonctions dépendent d'autres éléments de contexte et que tous les passer alourdisse vraiment l'écriture, c'est de rassembler ces éléments dans une seule structure, et de passer uniquement cette structure aux fonctions en ayant besoin, que ce soit en tant qu'argument classique, ou que ce soit en faisant de ces fonction non plus des fonctions libres, mais des fonctions membres d'une classe dont le rôle serait de maintenir ce contexte de calcul.

    Remplacer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void f(Topology const &t, double x1, double x2)
    {
      // ...
      w = t.max_sim_time;
      g(t, z);
      // ...
    }
     
    int main()
    {
      Topology t(...);
      cout << f(t, x1, x2);
    }
    Non pas par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void f(double x1, double x2)
    {
      // ...
      w = globalTopology().max_sim_time;
      g(z);
      // ...
    }
     
    int main()
    {
      Topology t(...);
      setGlobalTopology(t);
      cout << f(x1, x2);
    }
    Mais par :
    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
    class Simulation
    {
      void f(double x1, double x2);
      void g(double d);
      Topology &myTopo;
    };
     
    void Simulation::f(double x1, double x2)
    {
      // ...
      w = myTopo.max_sim_time;
      g(z);
      // ...
    }
    int main()
    {
      Topology t(...);
      Simulation s(t /*plus autres params*/);
      cout << s.f(x1, x2);
    }
    Je ne dis pas que cette méthode est supérieure à la première dans l'absolu, il y a juste des cas où elle est plus pratique, en particulier si la classe Simulation doit aussi conserver d'autres états que la topologie. Et des cas où passer l'argument est plus simple.

    Mais j'ai du mal à voir des cas où le singleton est supérieur.
    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.

  9. #9
    Invité
    Invité(e)
    Par défaut
    dans ton deuxième exemple, tu es en train d'écrire un wrapper uniquement pour stocker Topology...
    Tu crèes en plus une dépendance sur Topology car dans l'interface de ton wrapper (contrairement à accédé via singleton depuis cpp)

    L'argument des tests unitaires est discutable. Il te suffit de supprimer le singleton à la fin de chaque test. On peut discuter si on tourne en parallèle, notamment, si on sein d'une méthode utilisant la variable globale celle-ci est altérée entre temps et corrompt de fait le traitement de la méthode.

    Toujours est-il que pallier ce problème équivaut à copier l'entité et introduire une désynchronisation, ce qui est accessoirement dangereux

    Je suis d'accord que le singleton n'est pas la meilleure solution, ya toujours mieux, mais pour le coup, éviter de passer en paramètre partout me via cette méthode me semble ok.
    edit: mon petit doigt me souffle que c'est pour du driver pour un projet pas très gros, et que le projet est orienté plus transaction que services (spaghetti like)

  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 : 49
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par galerien69 Voir le message
    dans ton deuxième exemple, tu es en train d'écrire un wrapper uniquement pour stocker Topology...
    Si par deuxième exemple, tu veux dire celui avec Simulation, j'ai bien précisé que ça n'avait d'intérêt que si l'on devait au final avoir un état qui contenait bien d'autres choses que la topologie. Sinon, je n'ai pas compris ce que tu voulais dire.
    Citation Envoyé par galerien69 Voir le message
    Tu crèes en plus une dépendance sur Topology car dans l'interface de ton wrapper (contrairement à accédé via singleton depuis cpp)
    Il y a une dépendance sur la topologie, qu'on le veuille ou non. Cette dépendance est cachée (mais bien réelle) dans le cas du singleton, et bien visible dans mon cas. C'est justement le fait de cacher cette dépendance qui me gêne le plus dans ce pattern.
    Citation Envoyé par galerien69 Voir le message
    L'argument des tests unitaires est discutable. Il te suffit de supprimer le singleton à la fin de chaque test.
    Je ne suis pas certain de m'être bien fait comprendre. Quand on voit une fonction à tester qui a ce prototype :
    On se dit qu'on va devoir pour la tester uniquement lui donner diverses valeurs de d en entrée, et voir la fonction retournée. Maintenant, si on s'autorise à avoir un singleton dans le programme, dont on sait qu'il va modifier le comportement de tout un tas de fonctions sans que ce soit indiqué dans leur interface, que va-t-on faire ? Il va falloir :
    - Soit vérifier en regardant l'implémentation de f (et des toutes les fonctions appelées par f) si elle utilise ou pas le singleton, et dans le cas où elle l'utilise croiser les différentes valeurs en entrée de f avec différentes configurations possibles du singleton, pour vérifier sa valeur de sortie dans tous les cas.
    - soit faire de toute façon ce croisement, car même si f n'utilise pas le singleton à l'instant t, qui sait si elle ne l'utilisera pas à l'instant t+1 ? On ne peut jamais le savoir, car c'est un détail caché

    Dans le même cas, mais si on s'interdit un tel singleton, on sait rien qu'en regardant l'interface de la fonction combien de cas de tests il faut prendre en compte. Et si le développeur change d'avis, et ajoute la topologie en argument, le test unitaire ne compilera plus, on regardera ce qui se passe et on saura que les conditions d'usage de la fonction ont changé, et qu'il faut revoir les tests.

    Citation Envoyé par galerien69 Voir le message
    On peut discuter si on tourne en parallèle, notamment, si on sein d'une méthode utilisant la variable globale celle-ci est altérée entre temps et corrompt de fait le traitement de la méthode.

    Toujours est-il que pallier ce problème équivaut à copier l'entité et introduire une désynchronisation, ce qui est accessoirement dangereux
    Pourquoi copier ? Où as tu vu une copie de Topology dans un de mes exemples ?
    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.

  11. #11
    Invité
    Invité(e)
    Par défaut
    Cette dépendance est cachée (mais bien réelle) dans le cas du singleton, et bien visible dans mon cas. C'est justement le fait de cacher cette dépendance qui me gêne le plus dans ce pattern.
    Moins il y a de dépendances dans l'interface, mieux c'est.

    Maintenant, si on s'autorise à avoir un singleton dans le programme, dont on sait qu'il va modifier le comportement de tout un tas de fonctions sans que ce soit indiqué dans leur interface, que va-t-on faire ? Il va falloir :
    - Soit vérifier en regardant l'implémentation de f (et des toutes les fonctions appelées par f) si elle utilise ou pas le singleton, et dans le cas où elle l'utilise croiser les différentes valeurs en entrée de f avec différentes configurations possibles du singleton, pour vérifier sa valeur de sortie dans tous les cas.
    - soit faire de toute façon ce croisement, car même si f n'utilise pas le singleton à l'instant t, qui sait si elle ne l'utilisera pas à l'instant t+1 ? On ne peut jamais le savoir, car c'est un détail caché
    C'est quasiment pareil quand tu passes par paramètre.
    ton exemple avec les double est trop simpliste. Si tu passes ton Topology de methode en methode, c'est exactement la même chose qu'utiliser une variable globale (ou singleton).

    Pourquoi copier ? Où as tu vu une copie de Topology dans un de mes exemples ?
    J'étais pas clair. Tu chipotes sur t et t+1 car la fonction modifie la variable globale. Je dis oui c'est vrai, la fonction peut avoir un comportement byzarre. SI c'est le cas alors :
    pour résoudre ce problème il faut introduire une desynchronisation.

    Que tu aies une référence ou un pointeur ou une variable globale, c'est pareil.

    sans que ce soit indiqué dans leur interface
    Certes.

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par galerien69 Voir le message
    Moins il y a de dépendances dans l'interface, mieux c'est.
    Quitte à avoir une dépendance, je préfère très franchement qu'elle soit présente dans l'interface (car on peut se contenter d'une déclaration anticipée, mais, au moins, on sait que la dépendance existe) plutot que d'avoir une dépendance "cachée", dont rien ne dit dans l'interface qu'elle existe, mais qui nécessite, de toutes manières, l'inclusion du fichier d'en-tête correspondant dans l'implémentation...

    Au moins, on a la certitude que seules les fonctions qui exposent effectivement cette dépendance l'utiliseront, certitude que l'on ne pourra pas avoir avec une variable globale

    C'est quasiment pareil quand tu passes par paramètre.
    ton exemple avec les double est trop simpliste. Si tu passes ton Topology de methode en methode, c'est exactement la même chose qu'utiliser une variable globale (ou singleton).
    Justement, non...

    Déjà, une variable globale ou un singleton va exister en dehors de tout scope, alors que la variable transmise à une fonction comme argument n'existera que dans la portée dans laquelle elle a été déclarée.

    De plus, cela permet, comme je l'ai fait remarquer plus haut, de s'assurer que seules les fonctions qui en ont réellement besoin peuvent y accéder, chose pour laquelle on ne peut avoir strictement aucune certitude en cas de variable globale ou de singleton

    Que tu aies une référence ou un pointeur ou une variable globale, c'est pareil.
    Non, quand tu passes une référence ou un pointeur en argument, tu dis explicitement que la fonction a besoin de l'argument pour travailler, et tu sais donc que toute modification apportée au type de l'argument risque, d'une manière ou d'une autre, d'impacter sur la fonction.

    Lorsque tu travailles avec une variable globale ou avec un singleton, il t'est beaucoup plus difficile de t'assurer du nombre de fonctions qui l'utilisent et donc de prévoir quelles fonctions seront impactées par un éventuel changement
    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

  13. #13
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par galerien69 Voir le message
    Moins il y a de dépendances dans l'interface, mieux c'est.
    Moins il y a de dépendances, mieux c’est. Mais des dépendances cachées, c’est pire que des dépendances explicites. Relis l’argumentation de Loïc, notamment la partie sur les tests unitaires qui est très pertinente.

    Et sinon, raisonnons un peu en terme de contrat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    double f(double monparametre)
    {
        REQUIRE(monparametre > 0); // OK
        REQUIRE(TOPOLOGY::instance()->state == initialized) // WTF*???
        /* … */
    }
    Si ce genre de chose ne te choque pas, je ne sais plus quoi te dire. Les préconditions d’une fonction doivent porter sur ses paramètres (ça inclut this dans le cas des fonction membres), pas sur des globales absolument pas maîtrisées.

  14. #14
    Invité
    Invité(e)
    Par défaut
    Déjà, une variable globale ou un singleton va exister en dehors de tout scope, alors que la variable transmise à une fonction comme argument n'existera que dans la portée dans laquelle elle a été déclarée.
    Ben non. Si t'as une référence ou un pointeur, son scope c'est pas la méthode.

    De plus, cela permet, comme je l'ai fait remarquer plus haut, de s'assurer que seules les fonctions qui en ont réellement besoin peuvent y accéder, chose pour laquelle on ne peut avoir strictement aucune certitude en cas de variable globale ou de singleton
    sans que ce soit indiqué dans leur interface
    Certes.
    J'ai pas ignoré ce commentaire, et je l'ai pas nié non plus.

    Citation:
    Que tu aies une référence ou un pointeur ou une variable globale, c'est pareil.
    idem celui qui la modifie impacte les autres.
    Le quasiment s'adressait à l'interface, le exactement à l'approche concurrente sur la variable.
    Relis l’argumentation de Loïc, notamment la partie sur les tests unitaires qui est très pertinente.
    Je l'ai lu et j'y ai répondu.

    Et sinon, raisonnons un peu en terme de contrat :
    Ah bon, il y a des préconditions sur Topology? Je ne savais pas.

    Enfin :
    Moins il y a de dépendances, mieux c’est. Mais des dépendances cachées, c’est pire que des dépendances explicites
    Le problème d'une dépendance cachée, c'est quand ton interface se voit rapporter plein de definition d'autres interfaces ce qui entre autre, pose un prob de bincompatibilité.
    Ici, tu peux défoncer Topology ca genera pas outre mesure quant a la bincompatibilité de la classe qui l'utilise.
    edit: En revanche forward declaration est également ok. L'argument de dépendance est caduque.

    edit2: j'aimerais quand même faire un point.
    Oui - pas de variable globale=on sait qui modifie quoi
    Non - passer par référence est plus safe qu'utiliser une globale
    Oui - copier Topology& dans toutes les méthodes qui l'utilisent, c'est lourd
    Oui - require sur une globale c'est suspect. La globale c'est pas pour faire un truc de fou
    Dernière modification par Invité ; 20/07/2012 à 10h34.

  15. #15
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par galerien69 Voir le message
    edit2: j'aimerais quand même faire un point.
    Oui - pas de variable globale=on sait qui modifie quoi
    Là-dessus, d’accord.

    Non - passer par référence est plus safe qu'utiliser une globale
    Là-dessus, pas d’accord (à cause du point 1). Passer par référence permet :
    - d’identifier les fonctions qui accèdent à l’objet
    - identifier les fonctions qui modifient l’objet (celles qui se contentent d’y accéder prennent un Topology const & en paramètre).

    C’est donc plus safe car le code client a plus de garanties sur ce que font les méthodes (même si tu as accès au code source de chacune, devoir vérifier pour toute fonction si elle modifie Topology, c’est lourd. Autant l’indiquer dans l’interface, ça fait partie de la sémantique de la fonction).

    Oui - copier Topology& dans toutes les méthodes qui l'utilisent, c'est lourd
    C’est verbeux, oui. Mais ça en vaut à mon avis la peine. Bien sûr, c’est à prendre au cas par cas. Il y a aussi le coût du passage de paramètre à prendre en compte, presque tout le temps négligeable.

    Oui - require sur une globale c'est suspect. La globale c'est pas pour faire un truc de fou
    Et pourtant, c’est quasiment obligatoirement le cas. Un code qui n’impose aucune précondition, c’est très rare (ce n’est pas parce qu’elles ne sont pas exprimés qu’elles n’existent pas).

  16. #16
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2012
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2012
    Messages : 2
    Points : 2
    Points
    2
    Par défaut
    Merci pour toute vos réponses pertinentes, je ne m'attendais pas à cela.

    Je dois vous avouer que je suis un peu perdu au milieu de toute ces propositions, ce code n'est pas le mien et je dois l'étudier afin d'inclure des fautes dans les éléments de simulation afin d'étudier les tolérances aux fautes sur un réseau de processeur.

    La simulation ce fait de manière parallèle donc le singleton semble à exclure. Je crois que cela est au final un mauvaise idée de vouloir partager cette élément car je vais trop modifier le code et ceci risque d'apporter des lenteurs ou/et des complications

    C'était une erreur de conception que de vouloir le modifier, il s'avère qu'une personne de mon équipe a pensé à une autre approche afin d'inclure des fautes lors de la simulation sans toucher à la topologie.

    Je suis désolé de vous avoir pris votre temps en tout cas merci pour ce site et à tous ceux qui le font vivre

  17. #17
    Invité
    Invité(e)
    Par défaut
    (ce n’est pas parce qu’elles ne sont pas exprimés qu’elles n’existent pas)
    Si c'est pas exprimé c'est permis.

    Là-dessus, pas d’accord (à cause du point 1). Passer par référence permet :
    je rajoute une couche. Tu passes une référence. Ton objet est modifié.
    Faut pas chercher plus loin. La seule information de plus que tu as, c'est que tu sais qui modifie ton objet. Toujours est-il qu'il est modifié. C'est dans ce sens que j'écris que c'est pas plus safe, et je crois avoir dis la même chose depuis le début.

    Bien sûr, c’est à prendre au cas par cas
    Des alternatives que j'ai vues, c'est
    - tout passer en paramètre. J'appèle pas ca une solution. Mais bon, ok certains l'envisagent, pourquoi pas.
    - un semblant de pimpl, la variante est identique (moyennant les abstract et cie) si tu rajoutes des setters. Mais je suis d'accord que c'est une possibilité.

    Maintenant, il semblerait que le parallèlisme intervienne, c'est un problème autrement plus compliqué.

  18. #18
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par galerien69 Voir le message
    je rajoute une couche. Tu passes une référence. Ton objet est modifié.
    Faut pas chercher plus loin. La seule information de plus que tu as, c'est que tu sais qui modifie ton objet. Toujours est-il qu'il est modifié. C'est dans ce sens que j'écris que c'est pas plus safe, et je crois avoir dis la même chose depuis le début.
    Ca ne montre rien.
    Si l'objet n'est pas passé en const&, oui il peut être modifié. Et alors ?
    Si la méthode ne modifie pas l'objet, on le passe en const&, et la lecture de son prototype permet de le savoir/en être conscient.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  19. #19
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par galerien69 Voir le message
    La seule information de plus que tu as, c'est que tu sais qui modifie ton objet. Toujours est-il qu'il est modifié. C'est dans ce sens que j'écris que c'est pas plus safe, et je crois avoir dis la même chose depuis le début.
    C’est là que tu prends le problème dans le mauvais sens. L’information importante, ce n’est pas qui modifie mon objet, mais qui ne le modifie pas.

    Un exemple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    if(topology.isValid())
    {
        do_something_that_require_topology_is_valid();
        do_something_else_that_require_topology_is_valid();
    }
    Qu’y a-t-il de faux dans ce code ? Comment le corriger ?

  20. #20
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par galerien69 Voir le message
    Si c'est pas exprimé c'est permis.
    Je dirais plutot "si c'est pas exprimé, c'est que l'on n'a encore trouvé aucune raison de l'interdire formellement"
    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

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Objets partagés par les noeuds d'un cluster JBoss
    Par jbossdev dans le forum Wildfly/JBoss
    Réponses: 1
    Dernier message: 08/09/2006, 13h48
  2. [Débutant] Utilisation d'un objet "partagé"
    Par Floyd_C dans le forum C++
    Réponses: 6
    Dernier message: 28/07/2006, 10h26
  3. Grouper des objets partageant des propriétés
    Par camboui dans le forum Algorithmes et structures de données
    Réponses: 6
    Dernier message: 06/04/2006, 19h01
  4. [Kylix] Objet Partagé et la CLX
    Par Sogarf dans le forum EDI
    Réponses: 3
    Dernier message: 25/05/2005, 11h21
  5. Peux t'on créer une copie locale de l'objet partagé?
    Par Anonymous dans le forum CORBA
    Réponses: 8
    Dernier message: 16/04/2002, 16h20

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