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 :

Copie, affectation, et pointeurs


Sujet :

C++

  1. #1
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 29
    Points : 19
    Points
    19
    Par défaut Copie, affectation, et pointeurs
    Bonjour,

    Je suis assez bien bloquée depuis hier sur un problème. J'ai un niveau assez basique en C++...
    J'ai écrit une classe qui est en gros une liste chaînée à l'aide de pointeurs : elle a un champ valeur, et un pointeur vers une autre liste, qui a elle-même une valeur etc.

    Bon, jusque là, ok.

    Le problème (entre autres) que je rencontre, c'est avec les constructeurs de copie et d'assignation. J'ai pensé y faire appel de façon récursive,
    Je reçois cette erreur à l'exécution (plus d'erreur lors de la compil) :

    00
    isEmpty : 1
    isEmpty : 0
    Erreur de segmentation (core dumped)
    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
     
    maListe::maListe(const maListe& ml) 
    {
    	push(ml.getData());
     
    	if (not ml.isEmpty())
    	{
    		maListe temp = ml;
    		while (not temp.isEmpty())
    		{
    			push(temp.getData());
    			temp = temp.getNextListe(); // retourne l'objet pointé par le pointeur, une liste, donc
    		}
    	}
    }
     
    maListe& maListe::operator=(const maListe &ml )
    {
     	if ( this != &ml )
     	{
     		push(ml.getInfo())
     		if (not ml.isEmpty())
     		{
    	   		maListe temp = ml;
    	   		while (not temp.isEmpty())
    	   		{
    	   			push(temp.getData());
    	   			temp = temp.getNextListe();
    	   		}		
     		}
    	}
       	return *this;
     }
    J'ai un main, qui fait basiquement cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    	maListe ml1;
    	cout << ml1.getNext() << ml1.getData() << endl;
    	maListe ml2;
    	cout << "isEmpty : " << ml1.isEmpty() << endl;
    	ml1.push(3);
    	cout << "isEmpty : " << ml1.isEmpty() << endl;
    	maListe ml3 = ml1;
    	cout << ml3.isEmpty() << endl;
    Quelqu'un pourrait me guider un peu, voire me guider vers des liens ? J'ai lu beaucoup de choses mais je m'y perds et finalement, je ne sais plus du tout comment procéder.
    :s

  2. #2
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Les seules references que j'ai trouve par-rapport au mot-cle not sont soit en C, soit en asm. Je pense qu'il vaut mieux eviter de s'en servir...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    cout << ml1.getNext() << ml1.getData() << endl;
    Pour moi cette ligne n'a aucun sens. As-tu une surcharge de l'operateur "<<" quelque part ? Quelque chose dans ce genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::iostream operator<<(std::iostream &c, const maListe &l);
    PS: par convention on a plutot l'habitude de faire commencer les noms de classe par une majuscule en C++.

  3. #3
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 29
    Points : 19
    Points
    19
    Par défaut
    J'ai commencé une surcharge de <<, mais je préférais ne pas l'utiliser pour le moment, parce que justement, comme j'ai quelques soucis pour parcourir ma liste...
    Cela dit depuis quelques heures, j'ai quand même progressé, je peux réessayer.

    Je ne savais pas pour not Merci !

  4. #4
    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
    Je n'ai pas tout compris, il manque des étapes dans le code que tu as posté pour tout suivre, mais ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    maListe::maListe(const maListe& ml) 
    {
    	push(ml.getData());
     
    	if (not ml.isEmpty())
    	{
    		maListe temp = ml;
    Tu définis un constructeur de copie de maListe, prenant en paramètre une autre liste, nommée ml. Jusque là, tout va bien.
    Mais à la dernière ligne, tu déclares une variable nommée temp que tu initialise à l'aide de ml, c'est à dire que tu appelles le constructeur de copie de maListe que tu es justement en train de définir.
    Le constructeur de copie s'appelle donc récursivement, et à moins que getData ne fasse des choses étranges, je ne vois rien qui empêche cette récursion d'être infinie, d'où l'explosion de la pile à un moment.
    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.

  5. #5
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 29
    Points : 19
    Points
    19
    Par défaut
    En effet. C'est d'ailleurs le problème, puisque je ne sais pas trop comment faire, du coup :s

  6. #6
    Membre habitué Avatar de robinsondesbois
    Homme Profil pro
    Etudiant
    Inscrit en
    Avril 2012
    Messages
    171
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Etudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2012
    Messages : 171
    Points : 173
    Points
    173
    Par défaut
    Pour effectuer une copie d'une liste chaînée tu doit en premier lieu redéfinir l'opérateur "=" pour les maillons de ta liste.
    Puis le constructeur par copie va parcourir tous les maillons fils de la chaîne et les copier.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    maListe::maListe(const maListe& ml) 
    {
        if (ml==NULL)
            return;
        *this = ml;
        maListe(ml.child);
    }
    Imaginons une liste :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    *-----*------*------*------*------NULL
    L'opérateur = va effectuer l'opération suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    *-----*------*------*------*------NULL
                    \       /
                     \--*--/
    Le constructeur par copie va effectuer l'opération suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    *-----*------*------*------*------NULL
                    \       
                     \--*------*------NULL/

  7. #7
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 29
    Points : 19
    Points
    19
    Par défaut
    Je ne suis pas certaine d'avoir compris, mais j'en ai l'impression.
    Je dois en tout cas conjointement définir mon opérateur d'assignation et de recopie car je vais avoir besoin de l'un pour faire l'autre etc.
    J'avais fini par imaginer un opérateur d'assignation vraiment bête du type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    this->data = ml->data;
    this->next = ml->next;
    mais je n'ai pas encore essayé ça non plus ... (j'ai d'autres projets sur le feu, m'y remets tout à l'heure)

    En tout cas, merci beaucoup. Je vais déjà essayer de faire ça, et voir comment ça évolue

  8. #8
    Membre habitué Avatar de robinsondesbois
    Homme Profil pro
    Etudiant
    Inscrit en
    Avril 2012
    Messages
    171
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Etudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2012
    Messages : 171
    Points : 173
    Points
    173
    Par défaut
    Les liste chaînées fonctionne de la façon suivantes :
    - une classe Node qui contient un pointeur sur le Node suivant et une donnée Data.
    - une classe List qui contient un pointeur sur le premier Node.

    La classe Node aura un constructeur par recopie et un opérateur "=" quasiment identique : ils copieront les données Data et les adresses des Node suivants.
    La classe List aura un constructeur par recopie et un opérateur "=" quasiment identique : ils copieront les Node de façon récursive. L'objectif final est d'obtenir deux listes complètement différentes.
    Tu peut vérifier tes résultats en comptant les new ou les instances d'objet.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    Node n1 =  Node(); // Objet créé
    Node *n2 = new Node(); // Objet créé
    Node n3 = Node(n1); // Objet créé
    List l1;
    l1.add(&n1);
    l1.add(n2);
    l1.add(&n2);
     
    List l2 = List(l1); // 3 Objets créés
    // 6 Nodes au final
    On pourrait se passer de la classe List mais personnellement j'aime bien la garder et mettre les algorithmes relatif aux listes dedans (affichage de tous les datas par exemple).

  9. #9
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par imperio Voir le message
    Les seules references que j'ai trouve par-rapport au mot-cle not sont soit en C, soit en asm. Je pense qu'il vaut mieux eviter de s'en servir..
    Il fait partie de la liste des mots-clé du C++, tout comme or, not_eq, etc.

  10. #10
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Citation Envoyé par oodini Voir le message
    Il fait partie de la liste des mots-clé du C++, tout comme or, not_eq, etc.
    Je me coucherai moins bete ce soir. Merci pour l'info !

  11. #11
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par oodini Voir le message
    Il fait partie de la liste des mots-clé du C++, tout comme or, not_eq, etc.
    Visual Studio ne le reconnait pas par défaut. Il faut soit désactiver les "extensions" soit inclure iso646.h (ciso646), comme en C. Mais c'est ici un non respect de la norme par VS. Je sais pas comment se comporte gcc ni clang la dessus.

  12. #12
    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 oodini Voir le message
    Il fait partie de la liste des mots-clé du C++, tout comme or, not_eq, etc.
    Par contre, certains compilos (Visual C++, je ne sais pas si ça a changé...) ne connaissent pas...
    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.

  13. #13
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 29
    Points : 19
    Points
    19
    Par défaut
    En théorie, oui, je sais qu'on devrait faire appel à un Node. Seulement pour mon travail, je ne peux pas en utiliser, ce qui me complique beaucoup la tâche.

  14. #14
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 29
    Points : 19
    Points
    19
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    maListe::maListe(const maListe& ml) 
    {
        if (ml==NULL)
            return;
        *this = ml;
        maListe(ml.child);
    }
    Merci beaucoup pour cette réponse bien détaillée, qui - je pense - m'aide à y voir plus clair.

    J'ai quand même un souci pour comprendre ça là :
    je ne fais que l'appeler, je n'enregistre pas ce nouveau maillon quelque part ?
    Parce que je ne comprends pas très bien... Comment copier le reste de ma chaîne.

  15. #15
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par progcyb Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    maListe::maListe(const maListe& ml) 
    {
        if (ml==NULL)
            return;
        *this = ml;
        maListe(ml.child);
    }
    Merci beaucoup pour cette réponse bien détaillée, qui - je pense - m'aide à y voir plus clair.
    Attention, niveau syntaxe il y a quelques problèmes.

    Une ref ne peut pas être nulle, et on ne compare pas une ref à NULL (d'ailleurs on préfère nullptr à NULL).

    L'appel d'un deuxième constructeur utilise cette syntaxe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    maListe::maListe(const maListe& ml) : maListe(ml.child) { }

  16. #16
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 29
    Points : 19
    Points
    19
    Par défaut
    Hum, oui, je vois.

    J'ai implémenté une méthode isEmpty, qui me retourne un booléen, si next vaut NULL.

    En gros :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    bool maListe::isEmpty() const
    {
     	return (this->next == NULL);
    }
    Du coup, si je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    maListe::maListe(const maListe& ml) 
    {
        if (ml.isEmpty())
            return;
        *this = ml;
        maListe(ml.child);
    }
    c'est mieux ?
    Ça ne me retourne pas d'erreur et ça a l'air de fonctionner mais bon...

    Merci beaucoup de m'aider

  17. #17
    Membre habitué Avatar de robinsondesbois
    Homme Profil pro
    Etudiant
    Inscrit en
    Avril 2012
    Messages
    171
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Etudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2012
    Messages : 171
    Points : 173
    Points
    173
    Par défaut
    - *this = m1; copie le maillon 1
    - maListe(ml.child); est un appelle de fonction récursive pour copier le maillon suivant.

    La première fois que tu fait maListe(m1) tu va copier le maillon 1, mais cette fonction va se rappeler toute seul en se passant m2 comme paramètre et donc copier m2, etc jusqu'a mx = NULL.



    PS : Je viens de me rendre compte que le code est faux. *this = m1 va remplacer la list par un maillon (pas bien). Il faut donc faire : this->lastMaillon->addChild(m1); this->lastMaillon = m1;
    - this = la liste
    - lastMaillon = le dernier maillon ajouter
    - m1 = le fil du dernier maillon puis il devient le dernier maillon.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    maListe::maListe(const maListe& ml) 
    {
        if (ml.isEmpty())
            return;
        *this = ml;
        maListe(ml.child);
    }
    C'est très mauvais. D'abord, on n'appelle pas operator= dans un constructeur de copie (surtout que normalement, operator= devrait être basé sur l'idiome copy-and-swap, donc lui appellera le constructeur de copie), et en plus tu rappelles un constructeur sur le fils, mais sur le même objet...

    En plus, d'après le nom de ta classe tu confonds liste chaînée et chaînon. Très mauvais aussi.
    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.

  19. #19
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 29
    Points : 19
    Points
    19
    Par défaut
    Si je comprends bien, je dois copier en commençant par la fin. J'avais commencé un truc du genre en utilisant des variables temporaires, plutôt qu'en déplaçant les maillons, je voulais modifier leurs valeurs et ajouter une sentinelle à la fin. Je ne sais pas si c'est une idée valable...
    Bon. Je commence à saisir, mais je n'arrive toujours pas à mettre en pratique ! C'est dur ! ^^

    Il me faut préciser que la ligne de commande pour compiler doit impérativement commencer par g++ ansi ce qui ne m'autorise pas de syntaxes très novatrices :s

  20. #20
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 29
    Points : 19
    Points
    19
    Par défaut
    "En plus, d'après le nom de ta classe tu confonds liste chaînée et chaînon. Très mauvais aussi. "

    C'est à dire que je ne décide pas de l'énoncé... Qui nous demande des choses un peu plus compliquées encore que ce que je dis ici, et encore moins cohérentes. Alors le nom... Franchement ^^
    À vrai dire, ce n'est même pas le vrai nom de ma classe.

Discussions similaires

  1. copie / affectation
    Par ikuzar dans le forum Débuter
    Réponses: 5
    Dernier message: 12/04/2011, 15h05
  2. operateur new et affectation de pointeur
    Par Nehmé dans le forum C++
    Réponses: 4
    Dernier message: 06/11/2009, 04h09
  3. Réponses: 4
    Dernier message: 04/02/2009, 16h08
  4. affectations différentes ? pointeurs ?
    Par Isendar dans le forum Algorithmes et structures de données
    Réponses: 8
    Dernier message: 13/05/2008, 21h04
  5. Affecter un pointeur de fichier a un autre
    Par dr_octopus74 dans le forum Bibliothèque standard
    Réponses: 8
    Dernier message: 16/03/2008, 09h33

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