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

SL & STL C++ Discussion :

Impl�mentation d'un singleton avec des std::shared_ptr


Sujet :

SL & STL C++

Vue hybride

Message pr�c�dent Message pr�c�dent   Message suivant Message suivant
  1. #1
    Nouveau membre du Club
    Homme Profil pro
    th�sard
    Inscrit en
    Novembre 2013
    Messages
    7
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : th�sard

    Informations forums :
    Inscription : Novembre 2013
    Messages : 7
    Par d�faut Impl�mentation d'un singleton avec des std::shared_ptr
    Bonjour � tous,

    Je viens � vous car je me heurte � un probl�me que je n'arrive pas � comprendre.
    Je tente d'impl�menter une classe singleton Template r�utilisable ; en m'inspirant de ce que je trouve sur le net, j'arrive � une premi�re impl�mentation (non encore thread-safe, mais c'est pas la question), avec des pointeurs classiques, qui marche :

    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
     
    #ifndef DEFINE_SINGLETON
    #define DEFINE_SINGLETON
     
    #include <iostream>
     
     
    // Classe de design pattern Singleton
     
    template <typename T>
     
    class Singleton {
     
    protected :
     
      // Pointeur vers l'instance unique
      static T* singletonPtr;
     
      // Constructeur et destructeur privés pour éviter l'appel depuis l'extérieur.
      Singleton () {}
      ~Singleton() {}
     
    public :
     
      // Méthode statique pour accéder à l'instance unique du Singleton ; celle-ci est
      // construite si elle n'était pas encore allouée.
      static T* getInstance() {
        if ( singletonPtr == nullptr ) singletonPtr = new T;
        return singletonPtr;
      }
     
      // Méthode statique pour détruire l'instance unique de T
      static void kill() {
        if ( singletonPtr != nullptr) delete singletonPtr;
        singletonPtr = nullptr;
      }    
     
    };
     
    // définition du singleton statique, intialisé sur nullptr
    template <typename T>
    T* Singleton<T>::singletonPtr = nullptr;
     
    // Classe test utilisant la classe ci-dessus
     
    class Test : public Singleton<Test> {
     
      friend class Singleton<Test>;
     
    private :
     
      // Constructeur et destructeur private pour éviter l'instanciation/destruction
      Test() {}
      ~Test(){}
     
      // Constructeur de copie et opérateur d'affectation interdits
      Test(const Test& other) = delete;
      Test operator=(const Test& other) = delete;
     
    public :
     
      // une méthode quelconque
      void doSomething() { std::cout << "doSomething" << std::endl; }
     
    };
     
     
    #endif // ndef DEFINE_SINGLETON
    et le main pour tester :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    #include <iostream>
    #include "SingletonSP.hpp"
     
    int main() {
      Test::getInstance()->doSomething();
      Test::kill();
      return 0;
    };
    Ceci compile et marche parfaitement.

    Ensuite, j'essaie une version avec des shared_ptr :

    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
     
    #ifndef DEFINE_SINGLETON
    #define DEFINE_SINGLETON
     
    #include <iostream>
    #include <memory>
     
     
    // Classe de design pattern Singleton
     
    template <typename T>
    class SingletonSP {
     
    protected :
      // Pointeur vers l'instance unique
      static std::shared_ptr<T> singletonPtr;
     
      // Constructeur et destructeur privés pour éviter l'appel depuis l'extérieur.
      SingletonSP () {}
      ~SingletonSP() {}
     
    public :
     
      // Méthode statique pour accéder à l'instance unique du Singleton ; celle-ci est
      // construite si elle n'était pas encore allouée.
      static std::shared_ptr<T> getInstance() {
        if ( !singletonPtr )  singletonPtr = std::make_shared<T>();
        return singletonPtr;
      }
     
      // kill() n'est a priori plus nécessaire, puisque singletonPtr sera détruit à la fin du scope
      // global, désalouant automatiquement l'objet pointé.
     
    };
     
    // la définition du singleton statique, non initailisée car encapsulée.
    template <typename T>
    std::shared_ptr<T> Singleton<T>::singletonPtr;
     
    // Classe test utilisant la classe ci-dessus
     
    class Test : public SingletonSP<Test> {
     
      friend class Singleton<Test>;
      friend std::shared_ptr<Test> std::make_shared<Test>(); // friend pour avoir accès au constructeur
      friend class std::shared_ptr<Test>; // friend pour avoir accès au destructeur
     
    private :
     
      // Constructeur et destructeur private pour éviter l'instanciation/destruction
      Test() {}
      ~Test(){}
     
      // Constructeur de copie et opérateur d'affectation interdits
      Test(const Test& other) = delete;
      Test operator=(const Test& other) = delete;
     
    public :
     
      // une méthode quelconque
      void doSomething() { std::cout << "doSomething" << std::endl; }
     
    };
     
     
    #endif // ndef DEFINE_SINGLETON
    et le main � peine modifi� :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #include <iostream>
    #include "SingletonSP.hpp"
     
    int main() {
      Test::getInstance()->doSomething(); // <-ligne 9
      return 0;
    };
    Et l�, la belle erreur de compilation, qui en clair me dit qu'� la ligne 9 je fais appel aux constructeur et destructeur de Test, ce qui est interdit car ils sont private.
    L'erreur exacte du compilo est, sans toutes les inclusions de la stl (que j'ai remplac�es par (...) pour rendre le truc lisible) :
    (...)
    SingletonSP.hpp:28:62: required from �static std::shared_ptr<_Tp1> SingletonSP<T>::getInstance() [with T = Test]�
    main.cpp:6:9: required from here
    SingletonSP.hpp:52:3: error: �Test::Test()� is private
    Test() {}
    (...)
    main.cpp:9:2: required from here
    SingletonSP.hpp:53:3: error: �Test::~Test()� is private
    ~Test(){}
    (...)

    Voil�, j'imagine qu'il s'agit d'une subtilit� dans l'utilisation des shared_ptr que je ne vois pas, mais justement je ne la vois pas...
    Pr�cision, j'utilise g++ 4.8.1 avec les options -Wall, -Wextra et -std=c++11

    Merci d'avance,

    whityranger

  2. #2
    Membre Expert Avatar de jabbounet
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juin 2009
    Messages
    1 909
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 49

    Informations professionnelles :
    Activit� : Consultant informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 909
    Par d�faut Est-ce vraiment une bonne id�e
    Bonsoir

    je ne pense pas que le concept de singleton et de shared_ptr puisse faire bon m�nage.

    Comme pour la plupart des conteneurs de la stl (probablement presque tous) l'un des pr�-requis pour leur utilisation est de leur fournir des objets qui puissent-�tre construit par copie, Or c'est justement ce que l'on souhaite �viter avec le singleton.

    si on lit attentivement la doc d'origine
    http://www.boost.org/doc/libs/1_55_0...lt_constructor
    Every shared_ptr meets the CopyConstructible, MoveConstructible, CopyAssignable and MoveAssignable requirements of the C++ Standard Library, and can be used in standard library containers. Comparison operators are supplied so that shared_ptr works with the standard library's associative containers.
    d'ailleur le compilateur te dit clairement que pour ton exemple de code shared_ptr ne peut pas acc�der ni au constructeur Test::Test(), ni au destructeur Test::~Test() car ces dernier sont priv�s....

  3. #3
    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,

    Tout comme jabbounet, j'estime que le shared_ptr n'est sans doute pas adapt�, mais pour une autre raison : shared_ptr est un pointeur partag�.

    Autrement dit, shared_ptr a pour but de s'assurer que la m�moire allou�e � un objet sera correctement d�truite lorsque le dernier objet qui l'utilise est d�truit. Ce n'est pas le but du singleton qui est de fournir un objet dont on est sur qu'il existera toujours! Ce n'est donc pas ce qu'il te faut.

    Le but du singleton est de s'assurer qu'il n'y aura � tout instant qu'une seule et unique instance de ton objet. Or, si tu veux un pointeur unique, ce serait plut�t std::unique_ptr qu'il te faudrait.

    Cela prendrait une forme 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
    template <typename T>
    class Singleton{
        public:
            /* pour respecter ton code original(*) */
            static T* instance(){
               /* rendu obligatoire à cause de la présence de kill */
               if(! instance_.get())
                   instance_.reset(new T);
                return instance_.get();
            }
            /* pour respecter ton code original (*) */
            static void kill(){
                instance_.reset();
            }
    };
    static std::unique_ptr<T> Singleton::instance_= std::unique_ptr<T>(new T);
    (*) Typiquement, un singleton est construit au d�but de l'ex�cution du programme et d�truit lorsque le programme s'ach�ve. Et, lorsque le programme s'ach�ve, toute la m�moire allou�e � ce programme est automatiquement lib�r�e par le syst�me.

    Mais un singleton a aussi pour but de s'assurer que nous acc�derons toujours au m�me objet, quel que soit le nombre de fois que nous tenterons d'y acc�der.

    D�s lors, on peut d�cemment se poser la question : Pourquoi donner � l'utilisateur l'occasion de d�truire l'objet"

    Ceci dit, le probl�me vient de ce � quoi ton singleton accorde son amiti�.

    Je m'explique : Dans ta version originale, tu d�clares la classe Singleton<T> amie du singleton "concret". C'est ce qu'il faut faire, parce que c'est Singleton<T> qui va essayer d'appeler le constructeur de ton singleton concret.

    Le probl�me, c'est que dans ta version avec un shared_ptr, ce n'est pas Singleton<T> qui va faire appel au constructeur : c'est std::make_shared. Or, std::make_shared n'est pas une fonction membre de Singleton<T> : C'est une fonction libre.

    Tu en arrive donc � une situation dans laquelle ton singleton accorde son amiti� � "quelque chose" (comprends : Singleton<T>) qui n'en a que faire, mais qui n'accorde pas son amiti� � ce qui en a r�ellement besoin, � savoir std::make_shared.

    Tu as donc deux solution : Soit tu cr�es toi-m�me le shared_ptr, soit tu veilles � ce que ton singleton concret accorde son amiti� � ce qui en a vraiment besoin

    En outre, il est tout � fait possible d'�viter le recours au pointeur et � l'allocation dynamique de la m�moire lorsque tu envisages (l'anti) le patern singleon. Tu peux parfaitement d�finir une variable statique directement dans la fonction instance(), en veillant alors � renvoyer une r�f�rence au lieu d'un pointeur.

    Cela prendrait la forme 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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    /** le concept d'objet non copiable
      *
      * j'aime disposer d'une classe qui me permette de représenter
      * le concept d'objet non copiable.  Cela permet de rendre la
      * notion plus "conceptuelle" en plus de faciliter l'écriture ;)
      *
      * @note Cette classe est destinée à intervenir dans une relation d'héritage privé
      */  
    struct NonCopyable{
        NonCopyable(NonCopyable const &) = delete;
        NonCopyable & operator = (NonCopyable const &) = delete;
    };
    /* La classe de base pour tous les singleton
     *
     * Le but du singleton est d'assurer l'unicité de l'objet.
     * Il ne doit donc être ni copiable ni affectable
     */
    template <typename T>
    SingletonByRef : private NonCopyable{
        public:
            T & instance(){
                 static T obj;
                 return obj;
             }
    };
    /** Mon singleton concret
       *
       * Comme SingletonByRef<T> n'est pas copiable ni affectable,
       * cette classe ne l'est pas non plus du fait de l'héritage
    class MySingleton : public SingletonByRef<T>{
        friend class SingletonByRef<T>;
        public:
            void doSomething(){}
        private:
            MySingleton(){}
            ~MySingleton(){}
    };
    qui pourrait �tre utilis�e sous une forme proche de
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    int main(){
        MySingleton obj;
        obj.doSomething();
    }
    Cette mani�re de faire n'a que des avantages :
    1. Tu gardes la syntaxe d'acc�s "classique" au lieu d'utiliser la syntaxe d�di�e aux pointeurs (bon, c'est pas le plus gros avantage, mais c'en est quand m�me un )
    2. Tu �vites le recours au pointeurs et tous les probl�mes connexes
    3. Tu es sur que l'instance de ton singleton concret sera cr��e en temps opportun et qu'elle sera d'office d�truite � la fin de l'ex�cution du programme
    4. Tu n'a pas besoin d'exposer une fonction kill qui permet � l'utilisateur de d�truire ton singleton alors qu'il n'a simplement pas � le faire
    Enfin, je ne peux que m'insurger une fois de plus contre l'usage de cet anti pattern!!!

    Il faut bien te dire qu'une variable statique n'est jamais qu'une variable globale habilement d�guis�e qui flotte sur un oc�an de myst�re et que les variables globales, C'EST MAL.

    En plus, un singleton est, par d�finition, une variable qui est disponible PARTOUT. Si tu as besoin d'une telle variable, c'est tr�s certainement que tu as un gros probl�me de partage des t�ches dans le sens o� tu permet � trop de choses diff�rentes de faire la m�me chose. Avec, comme corollaire le fait que, quand tu seras confront� � un bug, tu devras parcourir tout ton code pour trouver tous les endroits o� une action particuli�re est entreprise afin de les corriger... Avec la quasi certitude d'en oublier syst�matiquement.

    Le meilleur moyen de n'avoir qu'un instance d'un objet est toujours de veiller n'en cr�er qu'une
    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

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    th�sard
    Inscrit en
    Novembre 2013
    Messages
    7
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : th�sard

    Informations forums :
    Inscription : Novembre 2013
    Messages : 7
    Par d�faut
    Merci pour vos deux r�ponses : celle de jabbounet pour l'aspect compr�hension technique, celle de koala01 pour la solution alternative plus robuste.

    Je rebondis dessus : je suis bien entendu conscient du fait que le singleton est une variable globale, et que ces derni�res sont souvent source de complications au d�buggage. Cependant, j'ai tendance � m'en servir uniquement pour deux types de choses : un conteneur g�rant des options connues uniquement � l�ex�cution (en g�n�ral une struct initialis�e en d�but de programme, c'est quelque chose que j'utilise surtout dans mes codes de calcul scientifique, pour g�rer l'abondance des informations affich�es dans le log par exemple), et les gestionnaires de ressources. En l'occurrence, il s'agit d'un jeu et de gestionnaires de ressources (pour l'instant textures, mais � venir sons etc...).

    Donc la question que je me pose est : y a-t-il mieux ? Je n'en ai pas l'impression. Les classes qui utilisent ces ressources n'ont pas � savoir comment es autres classes les utilisent, donc il me semble logique d'avoir un gestionnaire externe. Avoir plusieurs gestionnaires serait un g�chis de m�moire. Et en d�clarer un unique local au d�but de main pour le passer en param�tre suppl�mentaire � TOUTES les classes apparaissant ensuite et susceptibles de l'utiliser ou de contenir des classes susceptibles de l'utiliser me semble affreusement lourd pour pas grand-chose, d'autant plus que l'op�rateur de r�solution de port�e permet de savoir quand on joue avec une variable globale singleton bien plus simplement qu'avec une variable globale simple.

    Bref, si vous voyez plus simple, je suis preneur...

  5. #5
    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
    Et moi je vais te poser une autre question : Quelles sont les classes qui ont vraiment besoin d'avoir acc�s � toutes les informations que contiennent tes singletons

    Et si tu me r�pond "toutes", tu passes par la fen�tre Je te sugg�re d'aller faire un petit tour vers une discussion qui devrait t'aider � comprendre mon id�e. Apr�s tout, elle est r�cente et de nombreuses voies sont explor�es
    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

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    th�sard
    Inscrit en
    Novembre 2013
    Messages
    7
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : th�sard

    Informations forums :
    Inscription : Novembre 2013
    Messages : 7
    Par d�faut
    Alors, je n'ai pas encore d�cortiqu� la discussion que tu as mise en lien, mais en la lisant en diagonale, j'ai l'impression que ne ressortent que quelques grands principes applicables dans mon cas, tels que "une classe doit avoir un seul et unique but bien d�fini", que je m'efforce de respecter (m�me si je ne le fais sans doute pas parfaitement... ). Le fait est qu'il ne s'agit pas ici de g�rer une config dont les �l�ments accessibles doivent �tre d�finis avec soin, ni un transfert d'informations d'une source quelconque vers la classe qui se chargera de les traiter ; il s'agit de s'assurer qu'on ne charge en m�moire une et une seule fois des ressources partag�es, et en l'occurrence un seul type de ressource (histoire de bien s�parer les responsabilit�s) : les textures.

    Donc l�-dessus, se pose ta question :
    Quelles sont les classes qui ont vraiment besoin d'avoir acc�s � toutes les informations que contiennent tes singletons ?
    Et la r�ponse n'est pas "toutes", mais dans ce cas pas loin. J'accorde volontiers que le gestionnaire des polices ne sera utile qu'aux classes de Menus (et pourrait donc �tre instanci� comme un membre statique priv� de la classe m�re Menu, par exemple), que le gestionnaire des sons devra �tre limit� � quelques classes sur lesquelles je ne me suis pas encore pench�... Et dans ce cas, ok.
    Mais pour le manager de Textures, ben celles-ci sont utilis�es par les menus (pour les images de fond), par les personnages, les objets � l'�cran, la map, l'interface de jeu... Toutes classes qui sont assez nombreuses et n'ont pas grand-chose en commun (sauf les personnages et objets, qui d�rivent d'une m�me classe m�re Element dans ma conception actuelle).
    Je vais m�me plus loin : les Element n'ont pas vraiment besoin de ces Textures, ce sont des objets internes g�rant l'affichage (s�paration des t�ches) appel�s SpriteManager qui s'en servent, et ils ne s'en servent qu'� leur construction (pas besoin de garder une variable membre associ�e donc). Donc les Element n'ont m�me pas besoin eux-m�me de TextureManager, et il faudrait le passer � leur constructeur juste pour le transmettre � qui de droit ? �a ne me semble pas logique comme "s�paration des t�ches".

    Donc :
    1. soit j'instancie un Manager unique et je transmet une r�f�rence sur mon Manager dans tous les constructeurs de toutes les classes susceptibles de les utiliser ; �a implique de le passer en argument du constructeur des Element uniquement pour le passer ensuite au constructeur des SpriteManager... et �a me semble ne pas �tre le job de Element de g�rer les ressources. C'est peut-�tre plus propre, mais personnellement je trouve �a lourd si c'est juste utilis� � la construction.
    2. soit je place TextureManager::getInstance() en private et je d�clare en amies SpriteManager (comme �a les autres n'y ont pas acc�s), mais aussi tous ceux qui ont besoin de �a parce qu'elles n'utilisent pas les SpriteManager en interne (donc la Map, et toutes les classes filles de Menu, puisque l'amiti� n'est pas h�rit�e -> au secours )
    3. soit je retravaille les Menus pour qu'ils utilisent les SpriteManager en interne pour faire la 2. et n'avoir en friend que SpriteManager et Map -> d�j� mieux, mais �a me semble quand m�me rustine ; � savoir que pour des raisons d'optimisation, je pr�f�re g�rer Map sans SpriteManager mais de fa�on personnalis�e
    4. soit je garde un singleton global et j'essaie de faire confiance � mon �quipe de dev...

    J'ai l'impression que tu trouveras la 1. plus propre, mais je pense que cela alourdit l'�criture du code pour pas grand-chose... � moins que tu ne me prouves le contraire :p

    EDIT : je viens de penser � une 5e solution : puisque, � l'exception de Map, tous les objets affich�s peuvent le faire par l'interm�diaire d'un SpriteManager, je pourrais placer TextureManager (non singleton) comme variable statique priv�e dans la classe SpriteManager, et d�clarer les quelques m�thodes (� vue de nez seulement deux) de Map qui ont besoin de TextureManager comme friend de la classe SpriteManager (pour acc�der au TextureManager statique)... ainsi seuls les objets en ayant l'utilit� ont acc�s � TextureManager, et en ont m�me connaissance... �a me semble plut�t pas mal, j'aimerais vos avis sur ces 5 id�es

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

Discussions similaires

  1. Impl�mentation d'une DAL utilisant des proc�dures stock�es avec SQL Server
    Par youness78 dans le forum Windows Presentation Foundation
    R�ponses: 3
    Dernier message: 30/10/2013, 09h32
  2. R�ponses: 4
    Dernier message: 30/05/2011, 19h38
  3. R�ponses: 2
    Dernier message: 27/04/2009, 11h39
  4. sprintf avec des std::string
    Par Bart_lx dans le forum C++
    R�ponses: 13
    Dernier message: 07/12/2007, 09h10
  5. R�ponses: 1
    Dernier message: 26/06/2006, 11h33

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