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

Langage C++ Discussion :

[STL] Copier des listes


Sujet :

Langage C++

  1. #1
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 169
    Par défaut [STL] Copier des listes
    Bonjour,

    j'ai une classe contenant une std::list, et je veux lui donner un constructeur par copie. Donc, je dois copier la liste de l'argument. Pour ce faire, j'ai trouvé deux méthodes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      copy(arg.list.begin(), arg.list.end(), list.begin());
    et

    Sont-elles équivalentes, et si oui, laquelle est la plus "correcte" ?
    Merci d'avance.

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    780
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mai 2006
    Messages : 780
    Par défaut
    pour le premier cas il faut que ta liste cible fasse la même taille que la liste source. A moins que tu n'utilises un back_inserter par exemple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
      copy(arg.list.begin(), arg.list.end(), std::back_inserter( list ));
    Mais ça sera pareil que ton

    Mais n'oublie pas que si tes données membres n'ont pas de mémoire allouée dynamiquement, C++ te construit tout seul un copy constructor qui correspond à des besoins basiques.

    ( est-ce une liste de pointeurs? )

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    110
    Détails du profil
    Informations personnelles :
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2009
    Messages : 110
    Par défaut
    Bonjour,

    D'après la doc cplusplus l'opérateur = est à mon sens le plus adapté à ce que tu veux faire.
    Tu peux aussi utiliser copy surtout si tu veux copier qu'une partie de ta liste par exemple.

  4. #4
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 169
    Par défaut
    Tout d'abord, merci à vous deux d'avoir répondu si vite.

    Mais n'oublie pas que si tes données membres n'ont pas de mémoire allouée dynamiquement, C++ te construit tout seul un copy constructor
    C'est à dire que que si dans ma classe, ma liste est statique, je n'ai même pas besoin de créer mon constructeur par copie ?

    Et ensuite, si je veux faire mon constructeur par copie moi-même,
    fait une copie conforme de ma liste tout seul comme en grand ?

    PS: je crois que j'ai compris, mais c'est simplement pour être sûr.

  5. #5
    Membre émérite
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    780
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mai 2006
    Messages : 780
    Par défaut
    statique? comme dans "static"?

    Ce que je veux dire c'est:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class A
    {
    public:
     
    private:
        std::list< std::string > mList;
        int mB;
    };
    n'a pas besoin de constructeur par copie défini par l'utilisateur, le compilo s'en charge tout seul.

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Salut,

    La première solution rajoutera (une copie du) le contenu de la liste de l'argument au début celui de la liste de l'objet en cours de construction.

    Ce n'est pas *forcément* faux, mais cela pourrait présenter des problème si la liste de l'objet en cours n'est pas vide, car tu aurais alors dans la liste le contenu "copié" +... le contenu d'origine de la liste.

    On peut décemment estimer que, si c'est la seule action que tu mène (sur la liste en tout cas) dans le constructeur par copie, ce risque n'est pas particulièrement problématique

    Cependant, il est préférable de restreindre l'usage de copy aux cas où, justement, tu souhaite rajouter le contenu d'une collection dans une collection non vide

    La deuxième crée une copie de la liste de l'objet passé en argument et l'assigne à la liste de l'objet en cours (mais il n'est pas impossible que, en interne, cela se traduise effectivement par l'appel à du copy... il faudrait voir dans le constructeur par copie et l'opérateur d'affectation de std::list pour s'en assurer )

    C'est, quoi qu'il en soit, beaucoup plus simple à écrire, et cela a l'avantage de t'assurer que le contenu de la liste de l'objet en cours ne sera au final absolument pas différent de la liste de l'objet passé en argument (même si, d'aventure, il y avait eu quelque chose dans la liste de l'objet en cours).

    A choisir, j'utiliserais donc cette deuxième solution lorsqu'il s'agit de... copier un objet.

    Cependant, il y a une troisième solution, qui est préférable aux deux que tu as déjà signalée: la liste d'initialisation.

    En effet, les constructeurs ont cette particularité de permettre l'utilisation de "liste d'initialisation".

    Elles permettent, tout simplement, d'appeler un des constructeurs existant du membre en cours de construction.

    C'est, d'ailleurs, la seule solution acceptable (dans le sens où ce sera la seule solution acceptée par le compilateur) pour construire le membre d'une classe si, pour des raisons qui ne peuvent être que valables, ton objet venait à ne pas avoir de constructeur ne prenant pas d'argument.

    Dans le constructeur par copie, la liste d'initialisation est simplement composée de l'appel du constructeur... par copie de chacun des membres.

    Cela prendrait donc la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    MaClass::MaClass(Maclasse const & rhs):liste(rhs.liste),
             membre1(rhs.membre1)/*, et ainsi de suite */
    {
    }
    Cependant, il faut être conscient que:
    1- La sémantique de copie et d'assignation est rarement compatible avec une sémantique d'entité (en gros, avec des objets polymorphes)

    2- Par défaut (comprend: s'il ne trouve aucun équivalent dans ce que tu as écrit, et que tu ne t'es pas arrangé pour l'en empêcher), le compilateur fournit de lui-même un constructeur par copie et un opérateur d'affectation à toute classe (en plus d'ailleurs qu'un destructeur et un constructeur ne prenant pas d'arguments si (et seulement si) il n'y a aucun autre constructeur défini).

    Le constructeur par copie fourni par le compilateur appellera automatiquement.... le constructeur par copie de chacun des membres de la classe, dans l'ordre de leur déclaration.

    3- Il faut rester attentif au contenu de ta liste, car je me suis basé jusqu'à présent sur le fait que la liste contenait des objets.

    Si elle contient des pointeurs et surtout si la mémoire allouée à ceux-ci a été allouée dynamiquement, et qu'elle est destinée à être libérée(delete) pour chaque élément dans le destructeur de l'objet, il faudra mettre en oeuvre une copie beaucoup plus en profondeur, en parcourant manuellement tous les élément de la liste et en invoquant new de manière à copier chacun des élément pointé) afin d'éviter les risque de double tentative de libération de la mémoire.

    Cela se traduirait par un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    MaClass::MaClass(MaClass const & rhs)
    {
        for(std::list<Type*>::const_iterator it=rhs.liste.begin();it!=rhs.liste.end();
            ++it)
            liste.push_back(new Type( *(*it));
    }
    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

  7. #7
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 169
    Par défaut
    Citation Envoyé par nikko34 Voir le message
    statique? comme dans "static"?

    Ce que je veux dire c'est:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class A
    {
    public:
     
    private:
        std::list< std::string > mList;
        int mB;
    };
    n'a pas besoin de constructeur par copie défini par l'utilisateur, le compilo s'en charge tout seul.
    Oui, c'est bien ce que je voulais dire.

    @koala01:
    D'abord, merci pour ton explication claire et complète. Ensuite, j'ai effectivement une liste d'objet, donc pas de soucis pour la libération mémoire. Je vais finalement opter pour la solution de la liste d'initialisation.

    Merci à tous pour votre aide et votre rapidité, je passe le sujet en résolu.

  8. #8
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par CP / M Voir le message
    Je vais finalement opter pour la solution de la liste d'initialisation.
    Ce que voulais dire nikko34, c'est que si tous tes membres sont déjà copiables (sémantique de copie correcte) alors tu n'as pas besoin de définir un constructeur par copie. Le compilateur en fourni un par défaut qui copie chacun des membre triviaux par valeur et fait appel au constructeur de copie des autres membres. Cf F.A.Q. Quand dois-je définir un constructeur par copie ? et Sémantique de copie

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. copier des fichiers a partir d'une liste
    Par NicaeaCivitas dans le forum Windows
    Réponses: 2
    Dernier message: 11/07/2017, 15h23
  2. Réponses: 5
    Dernier message: 04/06/2014, 22h29
  3. Rechercher dans un fichier et copier la liste des fichiers
    Par bigs3232 dans le forum Shell et commandes GNU
    Réponses: 23
    Dernier message: 18/09/2011, 00h36
  4. Copier des cellules excel dans une liste déroulante vba
    Par Papillon34 dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 19/01/2010, 16h03
  5. Réponses: 4
    Dernier message: 26/02/2009, 16h58

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