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 :

Passer des paramètres à un singleton


Sujet :

C++

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut Passer des paramètres à un singleton
    Bonjour àvous,
    j'ai une appli qui implémente un DP singleton.
    J'aimerais savoir comment on peut passer des paramètres au constructeur ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class CApp
    {
    private:
    	int m_i1;
    	CApp(int i1): m_i1(i1) {}
    public:
    	static CApp& GetInstance() {
    		static CApp s_app;
    		return s_app;
    	}
    //Comment faire ...
    };

  2. #2
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Par défaut
    Hs: Personellemnt, j'ai tendance à préférer un pointeur dans mes Singletons.

    Sinon,bah tu modifie les paramètres de GetInstance de tel sorte que tu passe à ton objet tout ce que veux non ?
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  3. #3
    Membre confirmé
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2007
    Messages
    206
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 206
    Par défaut
    Salut olive_le_malin,

    Je ne suis pas certain que ce soit une bonne idée, mais si je devais le faire, j'ajouterais une méthode de classe pour spécifier la valeur des paramètres et je vérifierais à l'entré de cette méthode que la méthode GetInstance n'ait pas déjà été appelée sans quoi je leverais une exception.

    Voilà, en espérant que ça puisse aider

    Jérôme

  4. #4
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    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 296
    Par défaut
    Rappel: un singleton, c'est juste une variable globale déguisée pour faire bien en société.
    Donc, tu as aussi le droit de l'initialiser. Pire, si tu veux la construire avec un paramètre, cela veut dire que toute construction paresseuse est impossible.
    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...

  5. #5
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    En modifiant le mins possible ton code, je dirais comme ça non ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class CApp
    {
    private:
    	int m_i1;
    	CApp(int i1): m_i1(i1) {}
    public:
    	static CApp& GetInstance( int i = 0 ) {
    		static CApp s_app( i );
    		return s_app;
    	}
    //Comment faire ...
    };

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut
    Bonjour,

    Niamorh : oui bien sûr, on peut faire comme ça, mais ça m'embette un peu de toujours appeller une fonction avec un argument (par défaut). D'autant plus que dans le cas réel j'en ai 3, dont certains des objets ...

    Ainsi, je pense que je vais utiliser la méthode donnée dans le lien de Luc, qui différencie bien le createInstance(parametres...) et le getInstance(). L'inconvénient, c'est que là, on aura forcément un pointeur sur objet statique:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class CApp
    {
    private:
    static CApp* ms_app;
    };
    et un truc trés trés moche dans le cpp :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    CApp* CApp::ms_app = NULL;
    alors que dans mon code initial, je n'en avais pas ... juste un objet statique "caché" à l'intérieur d'une seule fonciton statique ...

    Mais bon ... faut bien faire avec.

    @+

  7. #7
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    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 296
    Par défaut
    ... vu ta contrainte/ton exigence, tu n'as pas le choix.

    EDIT:
    Enfin ... Tu pourrais rajouter une indirection (façon pimpl idiom p.ex.) à ton singleton si vraiment tu tiens à tout avoir dans une fonction plutôt qu'en variable (globale) statique de classe.

    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
    struct Singleton {
       Singleton & instance() { // à mettre ailleurs 
          static Singleton s;
          return s;
       }
       void create(params ....) {
          assert(!pimpl_);
          pimpl_ = new Pimpl(params....);
       }
       ...
    private;
       Singleton() : pimpl_(0);
       struct Pimpl { // à mettre ailleurs tant qu'à faire }
       Pimpl * pimpl_;
    };
    Mais franchement, on n'y gagne pas grand chose vu qu'il y a toujours besoin d'une construction explicite. Au lieu d'un Singleton::create(...), il faut appeler Singleton::instance()::create(...).
    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...

  8. #8
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Salut,

    Citation Envoyé par olive_le_malin Voir le message
    Mais bon ... faut bien faire avec.
    Ou pas !
    Ou plutôt ou sans (singleton), en gérant correctement les dépendances entre objets (et composants)...

    MAT.
    (membre du comité de soutient à ceux qui font passer des entretiens et à qui on cite spontanément, et avec un grand sourire, le singleton comme exemple de design pattern, soit le cscqfpecsgsscedp ou un truc dans le genre)

  9. #9
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut
    ... vu ta contrainte/ton exigence, tu n'as pas le choix.
    OK, merci Luc

    Ou pas !
    Ou plutôt ou sans (singleton), en gérant correctement les dépendances entre objets (et composants)...
    Mat007, j'utilise ce singleton pour regrouper l'ensemble des fonctions "applicatives", ne faisant partie d'aucune classe, et ne regroupant finalement que des objets / variables / fonctions qui auraient dû être globale. Par exemple, la récupération des paramètres généraux de l'application, fonction d'initialisation, de lancement d'un serveur TCP, ... D'ailleurs, je l'appelle CApp. Que proposes-tu comme alternative ?

    @+

  10. #10
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Citation Envoyé par olive_le_malin Voir le message
    Que proposes-tu comme alternative ?
    Dans un premier temps le plus simple serait de créer cet objet dans le "main" et de le passer directement aux composants/classes qui en ont besoin.
    Je sais bien que le problème c'est que du coup tu vas sans doute devoir le passer en cascade à plein d'autres objets intermédiaires qui ne vont rien en faire que de le passer à leur tour 'plus bas'. C'est d'ailleurs un bon code smell au niveau du processus de création et qui sous-entend un très (trop ?) fort couplage, que justement l'utilisation de variables globales masque, et qui ne se serait vraisemblablement pas produit sans avoir utilisé de singleton en premier lieu.

    Faut pas se voiler la face, comme il a été dit, un singleton c'est une variable globale...

    MAT.

  11. #11
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Pour moi c'est un trop fort couplage. Mais comme je n'ai pas de solutions à proposer, je me retire de la pointe des pieds...

  12. #12
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut
    Citation Envoyé par Mat007 Voir le message
    Faut pas se voiler la face, comme il a été dit, un singleton c'est une variable globale...
    MAT.
    Oui, alors pour pas passer trop de temps, j'ai gardé cette implémentation :

    CApp.h :
    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
    class CApp
    {
    private:
    static CApp* m_pApp;
    CApp( unsigned short port, const std::string& add, const std::string& logDir) : ... {}
     
    public:
    ~CApp() {}
    static CApp* CreateInstance( unsigned short port, const std::string& add, const std::string& logDir) {
    	return ( m_pApp = new CApp(port, add, logDir) );
    }
    static CApp* GetInstance() {
    	return m_pApp;
    }
    void DeleteInstance() {
    	delete m_pApp;
    }
    };

    CApp.cpp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CApp* CApp::m_pApp = NULL;

    main.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
    25
    26
    27
    int main()
    {	
    	//Get the general parameters stored in our database
    	unsigned short port = 2001;
    	std::string add= "192.168.192.250";
    	std::string logDir = ".";
    	{
    		CDatabase db("MSA");
    		if( db.Open() == 0 )
    			db.GetParams( port, add, logDir );
    	}
     
    	//Create our unique global object
    	CApp* pApp = CApp::CreateInstance( port, add, logDir );
     
    	//Init our unique object instance
    	if( pApp && pApp->Init() == 0 )
    	{
    		//Wait for the end ...
    		pApp->WaitForExit();
    	}
     
    	//Delete the unique object
    	pApp->DeleteInstance();
     
    	return 0;
    }

  13. #13
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par Mat007 Voir le message
    Dans un premier temps le plus simple serait de créer cet objet dans le "main" et de le passer directement aux composants/classes qui en ont besoin.
    Je sais bien que le problème c'est que du coup tu vas sans doute devoir le passer en cascade à plein d'autres objets intermédiaires qui ne vont rien en faire que de le passer à leur tour 'plus bas'. C'est d'ailleurs un bon code smell au niveau du processus de création et qui sous-entend un très (trop ?) fort couplage, que justement l'utilisation de variables globales masque, et qui ne se serait vraisemblablement pas produit sans avoir utilisé de singleton en premier lieu.

    Faut pas se voiler la face, comme il a été dit, un singleton c'est une variable globale...

    MAT.
    Un singleton est effectivement une variable globale... mais une variable globale n'est pas obligatoirement vouée aux flammes de l'enfer !

    Je m'explique:
    Il existe, de fait, au moins une variable 'globale' (au sens d'accès global) immuable: le thread courant. Et toute programmation dans un contexte OO peut se résumer à "l'utilisation de service avec des paramètres locaux". Donc, j'ai un objet, et j'ai besoin d'accéder à un service. Ce service peut être:
    - lié à l'objet lui même (membre).
    - lié au thread-courant (current-thread).
    - lié au contexte d'éxecution (current-process).

    Note: les deux derniers cas peuvent être passés par paramètres, mais dans ce cas, on fait de la programmation fonctionelle et non OO.

    Hors le C++ (comme tous les languages sans reflectivité) ne permet pas d'accéder "facilement" à une interface du thread-courant (ou du contexte d'éxecution):
    - Il faut définir un type pour l'identificateur de service (dans un langage avec reflectivité, on peut passer l'objet d'interface voulue).
    - Il faut définir un type de retour "fort" (sinon l'utilisation du service risque de se résumer à l'interface ultime 'string doCommand(string)'). Ce qui implique l'utilisation de RTTI (et du dynamic_cast), et surout l'utilisation d'une interface pour l'objet représentant le thread-courant, ou le contexte d'execution.

    Ceci menant imanquablement à:
    - COM d'un coté (serviceidentifier = CLSID, type de retour = IID), avec pour inconvéniant le "gros" travail d'implémentation à effectuer.
    - L'utilisation de globales de l'autre (comme le fait MFC par exemple).

    Mais bon... c'est juste my .02€

  14. #14
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    En effet, je ne crache pas forcément sur les globales non plus, mais il faut toujours respecter les deux impératifs de thread-safety et de réentrance.

    1. Thread-safety:
      • Toutes les variables globales au process doivent être protégées par des objets de synchronisation, ou être les objets de synchronisation eux-mêmes (et encore, leur initialisation n'est pas toujours thread-safe).
      • Toutes les variables globales au thread sont thread-safe tant qu'on n'en passe pas un pointeur à un autre thread.
    2. Réentrance: Plus compliqué, Mais généralement:
      • Il n'y a pas de problème de réentrance si la variable est initialisée une bonne fois pour toutes et immuable ensuite.
      • À partir du moment où une variable globale au thread possède une sémantique de pile, il est très probable que la réentrance soit assurée.
      • Je ne pense pas que la réentrance soit possible pour des variables globales au process, modifiables, autres que les objets de synchronisation.

    Exemples:
    • Les variables globales que j'ai employées ces derniers temps étaient toutes des variables globales au thread avec sémantique de pile, plus la variable liée au Thread-Local Storage et ses protections.
    • Les fonctions non-réentrantes du C (comme strtok()) peuvent être thread-safe ou non, selon l'implémentation. L'implémentation Microsoft est thread-safe.
    • La notion de "répertoire courant" n'est pas thread-safe sous Windows, car elle est globale au processus. Mais dans le contexte d'un seul thread, on peut fournir la réentrance en sauvant le répertoire courant et en le restaurant à la fin.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. Comment passer des paramètre a OpenRecordset
    Par molarisapa dans le forum Access
    Réponses: 2
    Dernier message: 09/03/2006, 17h14
  2. [JSP]Passer des paramètres dynamiques à un Flash
    Par paulo1b dans le forum Servlets/JSP
    Réponses: 1
    Dernier message: 27/11/2005, 21h29
  3. [Débutant][C#]Passer des paramètres à un exe
    Par GéniuS77 dans le forum Windows Forms
    Réponses: 13
    Dernier message: 05/07/2005, 16h55
  4. Réponses: 7
    Dernier message: 30/12/2004, 12h01
  5. passer des paramétres à un fichier sql
    Par vbcasimir dans le forum Oracle
    Réponses: 2
    Dernier message: 21/12/2004, 18h08

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