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 :

problème avec le constructeur de copie


Sujet :

C++

  1. #1
    Membre actif
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    630
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 630
    Points : 234
    Points
    234
    Par défaut problème avec le constructeur de copie
    Bonjour,

    J'ai défini un classe Personnage. J'essaie de copier le Personnage goliath vers le Personnage david comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     int main()
    {
    	Personnage goliath("Epée aiguisée", 20);
    	Personnage david = goliath;
    ...
    }
    Voici les constructeurs que j'ai crée dans la classe Personnage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Personnage::Personnage() : m_vie(100), m_mana(100)
    {
    	m_arme = new Arme();
    }
    Personnage::Personnage(string nomArme, int degatsArme) : m_vie(100), m_mana(100)
    {
    	m_arme = new Arme(nomArme, degatsArme);
    }
    Le compilateur me dit alors :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Undefined reference to 'Personnage::Personage(Personnage const&)
    Ma question :
    -- Le compilateur ne crée - t - il pas automatiquement le constructeur de copie ?
    -- le problème serait - il ailleurs ?

    Merci d'avance pour votre aide.

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

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Si. Sauf si tu en déclares un toi même. Peut-on voir à quoi ressemble la définition de ta classe ?

  3. #3
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par ikuzar Voir le message
    Voici les constructeurs que j'ai crée dans la classe Personnage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Personnage::Personnage() : m_vie(100), m_mana(100)
    {
    	m_arme = new Arme();
    }
    Personnage::Personnage() : m_vie(100), m_mana(100)
    {
    	m_arme = new Arme();
    }
    Deux fois la meme chose, c'est normal?

    Le compilateur me dit alors :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Undefined reference to 'Personnage::Personage(Personnage const&)
    Ma question :
    -- Le compilateur ne crée - t - il pas automatiquement le constructeur de copie ?
    Mon hypothese est que tu as declare mais pas defini le constructeur de copie. Si tu veux celui genere par defaut, il ne faut pas en declarer un.

  4. #4
    Membre actif
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    630
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 630
    Points : 234
    Points
    234
    Par défaut
    effectivement, je l'ai declaré et nn pas défini ...
    Merci.

  5. #5
    Membre actif
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    630
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 630
    Points : 234
    Points
    234
    Par défaut
    Sinon, j'ai une autre question, liée au constructeur de copie.
    -- j'ai deux Personnage david et goliath qui ont un pointeur arme pointant vers le meme objet arme (voir main ci-dessus).
    -- j'ai détruit david ( d'abord son arme, puis lui meme ), puis j'ai détruit goliath et ceux en fin de main( )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    goliath.~Personnage();
    david.~Personnage();
    Ma question :
    est-ce normal que le compilateur ne rale pas, que le programme ne plante pas ... ?
    En effet quand je détruit goliath l'arme disparait avec lui. Quand je tente de détruire david, le compilateur est censé cherche son arme ... NON ?

    Merci d'avance pour votre aide.

  6. #6
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par ikuzar Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    goliath.~Personnage();
    david.~Personnage();
    Les circonstances ou ce genre de syntaxe (appel explicite au destructeur) est un bon choix sont rares. Extremement rare. Je ne suis pas sur de l'avoir jamais utilise en dehors de programmes d'experimentation.

  7. #7
    Membre actif
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    630
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 630
    Points : 234
    Points
    234
    Par défaut
    Jean-Marc.Bourguet, j'ai pas très bien compris ce que t'a dit.

  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 : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Dit autrement, tu n'as dans 99,99% des cas, voire plus, pas besoin d'appeler le destructeur explicitement (ce que tu fais avec goliath.~Personnage(); )

    Dans ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int main()
    {
      Personnage goliath;
    }
    Le destructeur est automatiquement appelé quand la variable est détruite à la sortie de la fonction.

    Pour ton autre question, il faudrait voir un peu plus de code. Que fais tu dans le destructeur de Personnage ? Et dans son constructeur de copie ? Il y a de fortes chances que quelque-chose se passe en effet mal (soit une fuite mémoire, soit une double libération mémoire) mais pas à la compilation, à l'exécution, ce qui fait que peut-être ça ne se voit pas si le programme s'arrête juste derrière.

  9. #9
    Membre actif
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    630
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 630
    Points : 234
    Points
    234
    Par défaut
    D'accord. Maintenant je cherche à provoquer un plantage. Arme est un pointeur dans Personnage. Le constructeur de copie que j'ai crée dans Personnage copie le pointeur et non pas l'objet pointé. david et goliath possède alors le meme objet arme. Et je me demande pourquoi ca ne plante pas.

    Voici mon code :

    Personnage.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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    class Personnage
    {
        public:
     
    	Personnage();
    	Personnage(std::string nomArme, int degatsArme);
    	Personnage(const Personnage &personnageACopier);
        void recevoirDegats(int nbDegats);
        void attaquer(Personnage &cible);
        void boirePotionDeVie(int quantitePotion);
        void changerArme(std::string nomNouvelleArme, int degatsNouvelleArme);
        bool estVivant();
        void afficherEtat();
     
        ~Personnage();
     
     
        private:
     
        int m_vie;
        int m_mana;
    	Arme* m_arme;
        //std::string m_nomArme; // Pas de using namespace std, donc il faut mettre std:: devant string.
        //int m_degatsArme;
     
     
    };
    Personnage.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
    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
    //Personnage::Personnage() : m_vie(100), m_mana(100), m_nomArme("Epée rouillée"), m_degatsArme(10) {}
    Personnage::Personnage() : m_vie(100), m_mana(100)
    {
    	m_arme = new Arme();
    }
    //Personnage::Personnage(string nomArme, int degatsArme) : m_vie(100), m_mana(100), m_arme(nomArme, degatsArme) {}
    Personnage::Personnage(string nomArme, int degatsArme) : m_vie(100), m_mana(100)
    {
    	m_arme = new Arme(nomArme, degatsArme);
    }
     
    Personnage::Personnage(const Personnage &personnageACopier)
    {
        m_vie = personnageACopier.m_vie;
        m_mana = personnageACopier.m_mana;
        m_arme = personnageACopier.m_arme;
        //m_arme = new Arme(personnageACopier.m_arme);
     
    }
     
    Personnage::~Personnage()
    {
    	delete m_arme;
    }
    	void Personnage::recevoirDegats(int nbDegats)
    	    {
    		m_vie -= nbDegats;
    		if (m_vie < 0)
    			m_vie = 0;
    	    }
    		void Personnage::attaquer(Personnage &cible)
    		{
    			cible.recevoirDegats(m_arme->getDegats());
    		}
     
    	    void Personnage::boirePotionDeVie(int quantitePotion)
    	    {
    	    	m_vie += quantitePotion;
    	    	if (m_vie > 100)
    	    		m_vie = 100;
    	    }
     
    	    void Personnage::changerArme(std::string nomNouvelleArme, int degatsNouvelleArme)
    	    {
    	    	m_arme->changer(nomNouvelleArme, degatsNouvelleArme);
     
    	    }
     
    	    bool Personnage::estVivant()
    	    {
    	    	if (m_vie > 0)
    	    		return true;
    	    	else
    				return false;
    	    }
     
    	    void Personnage::afficherEtat()
    	    {
    	        cout << "Vie : " << m_vie << endl;
    	        cout << "Mana : " << m_mana << endl;
    	        m_arme->afficher();
    	    }
    Voici mon main :
    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
    int main()
    {
        // Création des personnages
        //Personnage david, goliath("Epée aiguisée", 20);
    	Personnage goliath("Epée aiguisée", 20);
    	Personnage david = goliath;
        // Au combat !
        goliath.attaquer(david);
        david.boirePotionDeVie(20);
        goliath.attaquer(david);
        david.attaquer(goliath);
        goliath.changerArme("Double hache tranchante vénéneuse de la mort", 40);
        goliath.attaquer(david);
     
        // Temps mort ! Voyons voir la vie de chacun...
        cout << "David" << endl;
        david.afficherEtat();
        cout << endl << "Goliath" << endl;
        goliath.afficherEtat();
        //goliath.~Personnage();
        //david.~Personnage();
     
        return 0;
    }
    et voici le resultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    David
    Vie : 40
    Mana : 100
    Arme : Double hache tranchante vénéneuse de la mort (Dégâts : 40)
     
    Goliath
    Vie : 80
    Mana : 100
    Arme : Double hache tranchante vénéneuse de la mort (Dégâts : 40)

  10. #10
    Futur Membre du Club
    Homme Profil pro
    Doctorant en Geomodélisation
    Inscrit en
    Octobre 2007
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Geomodélisation

    Informations forums :
    Inscription : Octobre 2007
    Messages : 7
    Points : 9
    Points
    9
    Par défaut
    Dans le destructeur de ta classe, l'arme est effectivement détruite l'instance de ta classe Personnage est ensuite détruite. Cela ne met pas pour autant le pointeur de l'autre instance à NULL. Cela peut parraitre étrange, mais sauf erreur de ma part, il n'est pas interdit d'appeler delete plusieurs fois sur un même pointeur.

    Petit test pour s'en convaincre:
    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
    #include <iostream>
    #include <cstdlib>
     
    class A{
      public:
        A(const int& a);
      public:
        int a_;
    };
     
    A::A(const int& a):a_(a){
    }
     
    using namespace std;
    int main( int argc, char* argv[]){
     
      A* pA = new A(1);
      cout<<"Pointer is pA: "<<pA<<endl;
      cout<<"the contained integer is "<<pA->a_<<endl;
     
      delete pA;
      cout<<"Pointer is still pA: "<<pA<<endl;
      cout<<"the contained integer is now "<<pA->a_<<endl;
     
      pA=NULL;
      cout<<"Pointer is now pA: "<<pA<<endl;
      cout<<"But the next line crashes"<<endl;
      cout<<"the contained integer is now "<<pA->a_<<endl;
     
      return EXIT_SUCCESS;
    }
    Le code ne plante qu'à la dernière ligne car le pointeur est NULL.

    Tant que tu ne le fait pas pointer vers NULL appeler delete dessus ne te fera pas d'erreur de segmentation... enfin pas tout de suite et peut être pas du tout si tu as de la chance.

    Ce qui se passe ici c'est donc qu'à la fin de ta fonction main, un premier personnage est détruit détruisant avec lui l'arme et le pointeur vers l'arme qu'il possédait. L'autre personnage n'est pas encore détruit et son pointeur pointe toujours vers la zone mémoire ou se situait l'arme. Le danger c'est que si ce deuxième personnage essaye d'accéder à son arme avant d'être détruit, on ne sait pas trop ce qu'il va y trouver, mais probablement pas une arme en état de marche.

    Dans ton cas, soit tu considères qu'une arme est unique, dans se cas copier un personnage ne doit pas copier l'arme ; soit tu considères que l'arme peut être copiée et dans ce cas tu donnes au deuxième personnage une autre arme qui est une copie de la première.

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

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par cijad Voir le message
    Cela peut parraitre étrange, mais sauf erreur de ma part, il n'est pas interdit d'appeler delete plusieurs fois sur un même pointeur.
    Si, c'est interdit... Et en pratique, c'est le genre de chose qui va faire planter le programme, plus tard, dans du code sans aucun rapport
    Citation Envoyé par cijad Voir le message
    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
     
    int main( int argc, char* argv[]){
     
      A* pA = new A(1);
      cout<<"Pointer is pA: "<<pA<<endl;
      cout<<"the contained integer is "<<pA->a_<<endl;
     
      delete pA;
      cout<<"Pointer is still pA: "<<pA<<endl;
      cout<<"the contained integer is now "<<pA->a_<<endl;
     
      pA=NULL;
      cout<<"Pointer is now pA: "<<pA<<endl;
      cout<<"But the next line crashes"<<endl;
      cout<<"the contained integer is now "<<pA->a_<<endl;
     
      return EXIT_SUCCESS;
    }
    Ce code est incorrect dès le moment où tu déréférence pA après avoir fait le delete (je crois même qu'il est incorrect au moment où tu lis la valeur de pA pour l'afficher, mais n'ai pas le temps de vérifier).
    Incorrect = comportement indéfini = ça peut planter, déclencher une guerre thermonucléaire mondiale, ou simplement donner l'impression de marcher (ce qu'il fait ici).

  12. #12
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    je crois même qu'il est incorrect au moment où tu lis la valeur de pA pour l'afficher
    Confirme (du moins c'est la these de James depuis longtemps, j'ai jamais ete faire une exegese pour me faire ma propre opinion).

  13. #13
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    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
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Ce code est incorrect dès le moment où tu déréférence pA après avoir fait le delete (je crois même qu'il est incorrect au moment où tu lis la valeur de pA pour l'afficher, mais n'ai pas le temps de vérifier).
    Je confirme. l'utlisation d'un pointeur invalide, quelque soit cette utilisation (ne serait-ce que récupérer la valeur dudit pointeur) est interdite selon le standard C++. Seul un pointeur dont la valeur est NULL peut être lu ainsi ; pour tout autre pointeur, le comportement est indéfini.

  14. #14
    Futur Membre du Club
    Homme Profil pro
    Doctorant en Geomodélisation
    Inscrit en
    Octobre 2007
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Geomodélisation

    Informations forums :
    Inscription : Octobre 2007
    Messages : 7
    Points : 9
    Points
    9
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Citation Envoyé par cijad Voir le message
    Cela peut parraitre étrange, mais sauf erreur de ma part, il n'est pas interdit d'appeler delete plusieurs fois sur un même pointeur.
    Si, c'est interdit...
    Effectivement, merci de corriger, je me suis mal exprimé. C'est interdit car appeler une nouvelle fois delete sur une zone mémoire désallouée va avoir un comportement indéfini. Ce que je voulais dire c'est que cela ne va pas nécessairement faire planter ton programme, surtout si comme dans l'exemple de David et Goliath ici les deux appels sont très proche. C'est ce qui explique le comportement sur lequel s'interrogeait ikuzar :
    Citation Envoyé par ikuzar Voir le message
    Ma question :
    est-ce normal que le compilateur ne rale pas, que le programme ne plante pas ... ?
    En effet quand je détruit goliath l'arme disparait avec lui. Quand je tente de détruire david, le compilateur est censé cherche son arme ... NON ?
    Déjà, ce n'est pas un problème de compilation, c'est un aspect de gestion de la mémoire pendant l'exécution de ton programme, le compilateur n'a donc rien là voir là-dedans. Ensuite, c'est le problème des erreurs de mémoire : elles ne font pas systématiquement planter le programme. Ce n'est pas pour autant que le résultat est correcte. C'est ce que j'essayais d'illustrer avec mon petit exemple. Rassures-toi ikuzar, ton programme est donc incorrecte (comme celui que j'ai proposé ensuite pour l'illustrer) mais si ça donne l'illusion de marche comme le dit JolyLoic.

    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Citation Envoyé par JolyLoic Voir le message
    je crois même qu'il est incorrect au moment où tu lis la valeur de pA pour l'afficher
    Confirme (du moins c'est la these de James depuis longtemps, j'ai jamais ete faire une exegese pour me faire ma propre opinion).
    Là par contre je suis moins sur de comprendre, même si je vous crois sur parole. Pourquoi serait-il incorrect de simplement lire l'adresse contenu dans le pointeur. C'est peut être naïf mais je ne vois pas vraiment le danger. A moins que ce ne soit simplement quelque chose rendu incorrect par le standard pour bien signifier qu'un pointeur, une fois sa zone mémoire désallouée n'a plus de signification si il ne pointe par vers NULL.
    La bonne pratique serait d'ailleurs de toujours remettre un pointeur à NULL après un delete, non ?

  15. #15
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par cijad Voir le message
    Là par contre je suis moins sur de comprendre, même si je vous crois sur parole. Pourquoi serait-il incorrect de simplement lire l'adresse contenu dans le pointeur.
    Sur un x86 en mode segmente, charger un registre de segment invalide resulte en une interruption. Si on utilise ce mode (ni Windows ni Unix ne le fait, mais il y a eu des OS le faisant -- il me semble meme me souvenir que Windows pouvait le faire jusqu'a sa version 3), il est assez naturel d'invalider le segment lors de la liberation memoire.

Discussions similaires

  1. Réponses: 4
    Dernier message: 17/06/2011, 00h36
  2. Petit problème avec le constructeur par copie
    Par beegees dans le forum C++
    Réponses: 16
    Dernier message: 01/04/2008, 17h34
  3. [Debutant] Problème avec un constructeur par copie
    Par Drannor dans le forum Débuter
    Réponses: 5
    Dernier message: 12/03/2007, 10h15
  4. [Conception]Problèmes avec un constructeur dérivé
    Par Le Furet dans le forum Langage
    Réponses: 6
    Dernier message: 10/03/2006, 10h44
  5. Réponses: 4
    Dernier message: 14/01/2005, 20h41

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