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 :

vector de classe


Sujet :

SL & STL C++

  1. #1
    Invité
    Invité(e)
    Par défaut vector de classe
    Bonjour,

    Je souhaite utiliser un vecteur de classe :
    dans 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
    #include <iostream>
    #include <fstream>
    #include <vector>
    using namespace std;
    class bidon
    {
    public : 
          bidon(string a):file(a.c_str()){};
         bidon(){};//par defaut
          fstream file;
    };
     
    int main()
    {
        bidon monBidon("test.txt");//ca initialise bien (heureusement)
         vector<bidon> vBidon(2);//je tente d'allouer pour deux instances bidon
         return 0;
    }
    Le problème c'est qu'a la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      vector<bidon> vBidon(2);
    , ca compile pas, et j'ai les messages d'erreurs suivants : (je les tronque, sinon ca prend pas mal de place, si besoin j'écrirai tout)

    ios_base.h erreur <<std::ios::ios_base...
    vector.h instanciated from...
    iosfwd erreur a l'interieur du contexte
    streambuff erreur

    Je précise que je suis sous eclipse et que je debute en c++(donc STL)...
    J'ai cru lire que c'était plus "pratique" de stocker les objets directements et de ne pas passer par des pointeurs. Aussi, je m'entête un peu, mais je vois pas comment faire, et surtout je ne vois pas pourquoi le constructeur de vecteur peut pas allouer de la mémoire pour 2 fichiers.

    Je vois clairement que ca vient de fstream file, mais je ne vois pas comment y remédier

    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
    La copie de fstream est interdite, tu ne peux pas utiliser un code qui fait cette copie (dont ton vector).

    Quand ton objet qui contient le file est détruit, le file est aussi détruit et donc ferme le fichier. Quid de ta copie précédente?

    Peut-être vaut-il mieux juste stocker le nom du fichier et utiliser le file stream quand tu en as besoin?

  3. #3
    Invité
    Invité(e)
    Par défaut
    merci pour la réponse rapide.
    Du coup, je risque de devoir faire un retour sur la réalisation de ma classe fichier (qui contient le fstream)

    En fait, tout l'intérêt de ma classe fichier, c'est de pouvoir utiliser mon fstream. Ca me parait lourd de creer mon fstream a l'interieur de chacune des méthode de la classe (elles sont plutot pas mal appelées), du coup je pense que je vais opter pour des pointeurs.

    Je ferai ma suppression du vecteur manuellement...

    A moins que ca soit considéré comme sale?

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

    Le fait est que, lorsque tu demande à la classe vector de réserver directement un certain nombre d'éléments (c'est ce que tu fais en utilisant ce constructeur de la classe vector , tu induis le fait qu'il y aura création d'une variable temporaire du bon type lors de la première insertion, puis qu'il y aura copie de cette variable temporaire dans les suivantes

    Le problème vient du fait que... un objet de type fstream n'est pas copiable ...

    D'ailleurs, à l'usage, ta manière de faire risque fort de t'apporter quelques soucis, car, cela signifie que tu devra en permanence (à moins que tu aie la certitude que tu n'aura jamais qu'un nombre ferme et définitif d'objet) te poser la question de savoir si tu peux "simplement" rajouter un objet dans le nombre de ceux que tu as prévu ou si tu dois commencer à "en rajouter un"...

    C'est la raison pour laquelle il ne faut simplement pas réserver l'espace pour maintenir tes différents objets, et te "contenter" de les ajouter un à un de manière classique

    De plus, une classe dans laquelle il y aurait un flux fichier non initialisé ne serait - a priori - pas très intéressante

    En outre, l'utilisation de fstream indique - de prime abord - que tu veux pouvoir utiliser ta classe pour la lecture comme pour l'écriture...

    Comme il ne sert - finalement - pas à grand chose qu'une instance donnée de ta classe permette les deux, il serait sans doute opportun de prévoir un argument de plus dans le constructeur qui indiquerait si l'objet a pour but la lecture ou l'écriture...

    Au final, la classe pourrait donc ressembler à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class bidon
    {
        public:
            bidon(const std::string& fname/*voir plus loin*/, 
                  ios_base::openmode mode): file(fname.c_str(),mode){}
        private:
            fstream file;
    };
    et tu pourrais l'utiliser, simplement, sous 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
    int main()
    {
        vector<bidon*> tab;
        tab.push_back(new bidon("fichier",ios_base::out));/* ouvert en lecture */
        tab.push_back(new bidon("temp",ios_base::in)); /* ouvert en écriture */
        /*...*/
        /* ne pas oublier de libérer l'espace mémoire alloué lorsqu'il est devenu
         * inutile
         */
        return 0;
    }
    En ce qui concerne le changement du paramètre de type string...

    Il faut savoir que, quand tu ne passe pas un objet par référence, tu provoque la création d'une variable temporaire qui est la copie de la variable passée lors de l'appel...

    Lorsqu'il s'agit de classe, cela peut représenter énormément de travail que de créer une copie de l'objet pour l'utiliser en local, qui sera de toutes manières détruite une fois que l'on quitte la fonction, ce qui peut également représenter beaucoup de travail (sans compter quelques problèmes particuliers si la classe en question utilise des pointeurs alloués dynamiquement)...

    C'est la raison pour laquelle la bonne habitude à prendre est de systématiquement passer les classes et structures sous la forme de référence, ce qui permet d'éviter le travail de copie (et de destruction).

    Si la fonction ne doit effectuer aucune modification dans l'argument, il est en outre largement préférable, etant donné que l'on travaille sur un alias de la variable qui est passée lors de l'appel, de déclarer cet argument constant, afin d'éviter les problèmes éventuels de modification non voulues de la variable originelle.
    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

  5. #5
    Invité
    Invité(e)
    Par défaut
    excellent, du coup j'ai même plus de questions à poser!
    ...
    pour l'instant

  6. #6
    Invité
    Invité(e)
    Par défaut
    En fait, si!

    Toujours un problème avec le fichier.

    Petit bilan:
    compte tenu de ma classe Fichier qui ne fait que des acces en écriture, j'ai utilisé un ifstream pour éviter d'avoir à faire des tests quant au mode d'ouverture (ios_base::out).

    Voilà toujours ma classe bidon :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class bidon
    {
        public:
            bidon(const string &nomFichier):fichier(nomFichier.c_str()){};
     
            void Afficher()const{(fichier.good())?cout<<"stream ok"<<endl:cout<<"erreur" <<endl;};
        protected:
           ifstream fichier;
    };
    A partir de là, j'utilise mon vector : vector<bidon*> v;
    Donc l'initialisation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int main()
    {
    vector<bidon*> v(2);//en fonctionnement normal je connais la taille
    v[0]=new bidon("test.txt");
    v[1]=new bidon("test2.txt");
    v[0]->Afficher();
    v[1]->Afficher();
     
    return 0;
    }
    Et là je ne vois pas. Sous mon IDE Eclipse, j'ai bien le message valide (stream ok) dans les deux cas, mais quand je lance a partir de la console, j'ai le message d'erreur qui s'affiche(erreur).

    Je pense fortement que le problème vient de la construction du ifstream lors de l'appel du constructeur ifstream dans le constructeur bidon, car avec un constructeur bidon
    , le message est "stream ok "
    bidon(const string &nomFichier):fichier(nomFichier.c_str()){};

    Une des possibilités qui me vient à l'esprit est que le chemin relatif du fichier test.txt est erroné lors de l'appel du programme en console et que l'ouverture rate alors et on a un échec du ifstream.

    Mais je ne suis pas sûr, peut-être est-ce une erreur dans le code que mon compilo laisse passer car erreur syntaxiquement correcte??

    Je suis sous ubuntu 8.10 et mon compilo
    g++
    options : -O0 -g3 -Wall -c -fmessage-length=0

    re Merci d'avance!

  7. #7
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Pourquoi utiliser un pointeur d'objet? Autant directement stocké l'objet c'est bien plus simple et moins dangereux. La preuve : ici t'a fait l'erreur! Tu alloues de la mémoire sans jamais la libérée !
    Consulte la faq pour voir comment 'vider' proprement un vector de pointeurs!

    Enfin ne t'embêtes pas et stock directement les objets.

  8. #8
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut
    Citation Envoyé par Goten Voir le message
    Pourquoi utiliser un pointeur d'objet? Autant directement stocké l'objet c'est bien plus simple et moins dangereux. La preuve : ici t'a fait l'erreur! Tu alloues de la mémoire sans jamais la libérée !
    Consulte la faq pour voir comment 'vider' proprement un vector de pointeurs!

    Enfin ne t'embêtes pas et stock directement les objets.
    Stocker un objet ne marcherait pas, std::ifstream n'est pas copiable.

  9. #9
    Invité
    Invité(e)
    Par défaut
    Ok,

    en fait, c'était relativement stupide, les fichiers texte etaient dans le dossier des sources, et mon "exe" etait dans le dossier debug, eclipse simule le fichier texte dans le dossier Debug (surement un temporaire).
    Du coup il suffisait de copier les fichiers texte dans le dossier Debug!

    PS:c'est vrai que c'est pénible de s'assurer que ya pas de fuites mémoires. J'imagine pas sur les gros projets...

  10. #10
    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
    @galerien69 il est en effet possible que le chemin vers le fichier ne soit pas bon.

    Ce qui arrive souvent avec un EDI, c'est qu'il utilise le dossier racine du projet comme dossier d'origine, alors que l'exécutable se trouve dans bin/Debug, bin/Release ou ...

    Essaie en recopiant l'exécutable dans le dossier racine, ou en donnant un chemin de fichier absolu, cela devrait résoudre le problème

    @Goten: comme on l'a fait remarquer pour les fstream, le constructeur de base est d'accessibilité privée, ce qui rend les classes ifstream et ofstream non copiable.

    On ne peut donc pas utiliser une instance normale de la classe bidon car elle devient - à moins de "jouer" à redéfinir le constructeur par copie et l'opérateur d'affectation - elle aussi non copiable (vu qu'il est impossible d'en copier l'un des membres).

    C'est la raison pour laquelle la gestion de la classe bidon sous la forme d'un pointeur
    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

  11. #11
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Autant pour moi... je venais de me lever et j'avoue ne pas avoir lu l'ensemble du code :/.

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

Discussions similaires

  1. Vector et classes abstraites
    Par vbaddict44 dans le forum C++
    Réponses: 11
    Dernier message: 17/07/2012, 16h18
  2. vector de classe templatée
    Par Lintel-oo dans le forum Langage
    Réponses: 3
    Dernier message: 29/04/2012, 16h59
  3. Vector et classe
    Par sheep_one dans le forum Débuter
    Réponses: 4
    Dernier message: 26/01/2012, 07h47
  4. Problème avec vector de classe template :(
    Par coyotte507 dans le forum Langage
    Réponses: 7
    Dernier message: 16/04/2008, 12h40
  5. [CONCEPTION] vector de classes heritées
    Par A-S-H dans le forum SL & STL
    Réponses: 9
    Dernier message: 28/12/2005, 09h50

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