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 d'un objet avec un attribut de type vector


Sujet :

C++

  1. #1
    Membre à l'essai
    Inscrit en
    Juillet 2008
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Juillet 2008
    Messages : 4
    Par défaut Copie d'un objet avec un attribut de type vector
    Bonjour,
    Je suis "débutant" en C++ et j'ai un problème :
    Comment peut on copier un objet qui a un attribut de type "vector" ? Je m'explique :

    J'ai essayé d'utiliser memcpy et j'ai écrit ce petit code de test :

    Voici mon fichier A.hpp :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #include <iostream>
    #include <vector>
    using namespace std;
     
    class A {
    public :
    	void printV(int i);
    	void addV(int i){v.push_back(i);}
    	void testAddV();
    private :
    	vector<int> v;
    };
    mon fichier A.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
     
    #include "A.hpp"
     
    void A::printV(int i)
    {
    	cout << v[i] << endl;
    }
     
    void A::testAddV()
    {
    	this->addV(1);
    	A* a2 = new A();
    	memcpy(a2,this,sizeof(*this));
    	cout << "a2->v[0] = ";
    	a2->printV(0);
    	this->addV(2);
    	cout << "a->v[0] = ";
    	this->printV(0);
    	cout << "a->v[1] = ";
    	this->printV(1);
    	cout << "a2->v[0] = ";
    	a2->printV(0);
    }
     
    int main()
    {
    	A* a = new A();
    	a->testAddV();
    	system("PAUSE");
    	return 0;
    }
    Voilà ce que j'obtiens en sortie :

    a2->v[0] = 1
    a->v[0] = 1
    a->v[1] = 2
    a2->v[0] = -17891602
    Appuyez sur une touche pour continuer...

    Cela veut dire dire que la commande "this->addV(2);" a bien fait son boulot en me rajoutant 2 à this->v mais elle m'a fait des changements bizarres sur mon a2->v[0] qui est devenu -17891602. Pourquoi ? et est-ce que memcpy(a2,this,sizeof(*this))" n'est pas supposée faire la copie de l'objet pointé par this dans un nouvel objet qui sera pointé par a2 ? quelle serait la solution ?

    Remarque : quand j'ai essayé avec un attribut plus simple (int par exemple) ça a bien marché : c'est à dire que la modification de l'attribut de l'objet d'origine n'avait aucune répercussion sur l'objet copié.

  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
    Ah !!!! JAMAIS de memcopy sur des objets non POD (Plain Old Data: des agrégat de types de base avec possibilité qu'il contienne lui même un POD).

    Etant donnée que ta classe ne gère pas dynamiquement de la mémoire, utiliser le constructeur de copie par défaut ferra très bien l'affaire (car std::vector un possède un).
    Ton code devient donc :

    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
     
    #include "A.hpp"
     
    void A::printV(int i)
    {
    	cout << v[i] << endl;
    }
     
    void A::testAddV()
    {
    	addV(1);
     
    	A* a2 = new A(*this); //ici appel au constructeur de copie par défaut.
     
    	cout << "a2->v[0] = "; a2->printV(0);
     
                    addV(2);
     
                    cout << "a->v[0] = ";  printV(0);
    	cout << "a->v[1] = " ; printV(1);
    	cout << "a2->v[0] = "; a2->printV(0);
     //manque un delete sur a2, ou alors utilise des objets statiques
    }
     
    int main()
    {
    	A a ; //pas besoin de new là
    	a.testAddV();
    	return 0;
    }
    Sinon, remarques en vrac, (pas toutes corrigées ici):
    • un new => un delete car sinon fuite de mémoire.
    • this-> ca alourdit généralement le code inutilement.
    • Dans ton cas pas, besoin de new dans le main, ni même dans testAddV.
    "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
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    memcpy c'est pour copier des séquences brutes d'octets, surtout pas des objets qui auront besoin d'exécuter leurs constructeurs par copie, destructeur ou opérateur =.
    Là par exemple tu vas fourrer dans a2->v les membres de this->v, qui sont vraissemblablement une taille et un pointeur vers le tableau. Ce qui fait que a2->v va pointer sur un tableau qui n'est pas le sien, ce qui est n'importe quoi.

    Heureusement le C++ est bien fait : std::vector est parfaitement copiable, et puisque std::vector est copiable, ta classe l'est aussi par défaut et tu peux donc utiliser le constructeur par copie ou encore l'opérateur =.

    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
    void A::testAddV()
    {
    	this->addV(1);
    	A* a2 = new A(*this);
     
    	cout << "a2->v[0] = ";
    	a2->printV(0);
    	this->addV(2);
    	cout << "a->v[0] = ";
    	this->printV(0);
    	cout << "a->v[1] = ";
    	this->printV(1);
    	cout << "a2->v[0] = ";
    	a2->printV(0);
    }

  4. #4
    Membre à l'essai
    Inscrit en
    Juillet 2008
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Juillet 2008
    Messages : 4
    Par défaut Résolu
    Merci, c'est exactement ce que je recherchait : comment construire un objet à partir d'un autre. Ça marche bien maintenant !

  5. #5
    Membre à l'essai
    Inscrit en
    Juillet 2008
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Juillet 2008
    Messages : 4
    Par défaut Quelques détails :
    Pour les this c'est sur que c'est lourd, j'avais mis ça juste pour être clair, sinon les delete il faudra que je m'y habitue là que je code en c++ : pas évident pour quelqu'un qui arrive du monde JAVA

  6. #6
    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
    Citation Envoyé par yassine480480 Voir le message
    Merci, c'est exactement ce que je recherchait : comment construire un objet à partir d'un autre. Ça marche bien maintenant !
    Ce qu'il faut comprendre, ce qu'utiliser le constructeur de copie par défaut( ~ celui généré par le compilateur) ne marchera bien que si tout tes attributs possède eux aussi un constructeur de copie appropié (~différent de celui par défaut si la classe gère dynamiquemnt de la mémoire).

    C'est l'exemple de ta classe : Utiliser le constructeur de copie par défaut marche très bien car std::vector en possède un, ce qui est aussi le cas de tous les conteneurs de la STL.

    Si std::vector n'en n'avait pas, tu serrai obligé d'en définir un. Tu devrais aussi définir un opérateur d'affectation, car définir l'un des deux (copie ou affectation) oblige à définir l'autre.
    "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)

  7. #7
    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 yassine480480 Voir le message
    Pour les this c'est sur que c'est lourd, j'avais mis ça juste pour être clair, sinon les delete il faudra que je m'y habitue là que je code en c++ : pas évident pour quelqu'un qui arrive du monde JAVA
    Bah... faut les faire aussi... la plupart du temps... Le GC fait beaucoup de chose automatiquement, mais il ne permet d'oublier la gestion mémoire !
    Le probleme de Java c'est qu'on sait jamais trop quand les faire ces delete, et ni même quel est leur noms !

    Essayes d'ouvrir des stream, et ne jamais les fermer explicitement ... tu verras

  8. #8
    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
    Essayes d'ouvrir des stream, et ne jamais les fermer explicitement ... tu verras
    Et tout ce passera bien grace au RAII (si les streams ne sont bien sur pas allouer par new )
    "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)

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 11/01/2012, 17h28
  2. Réponses: 5
    Dernier message: 12/01/2011, 21h15
  3. Copie d'une table avec une colonne du type image
    Par mma67 dans le forum Développement de jobs
    Réponses: 6
    Dernier message: 12/02/2010, 19h13
  4. Tableaux d'objets avec plusieurs attributs
    Par wafiwafi dans le forum Langages de programmation
    Réponses: 2
    Dernier message: 20/08/2009, 15h02
  5. probleme avec les attributs de type ID
    Par ben83 dans le forum XML/XSL et SOAP
    Réponses: 1
    Dernier message: 01/01/2006, 21h49

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