Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème de compréhension

    21 août 2019 à 11:31:44

    Salut, je commence à apprendre le c++ et je remarque que les chose ne fonctionne pas comme en C.

    Première chose le type de retour string. Ma fonction créer renvoie un type string mais le compilateur il veut pas... Je comprends pas trop pourquoi.

    #include "motMustere.h"
    
    using namespace std;
    
    int main() {
    	string const nomFichier("pendu.txt");
    	ifstream FluxLecturefichier(nomFichier);
    
    	if (FluxLecturefichier) {
    		string motMyst;
    	motMyst= choixDuMot(FluxLecturefichier); // ligne fausse
    
    
    
    	} else {
    		cout << "lecture impossible du fichier" << endl;
    	}
    
    	return 0;
    }
    string choixDuMot(ifstream flux){
    	int cptMot(0);
    			int cptChoix(1);
    			int ligneMot;
    			string ligneDico;
    			cout << "Choix du mot mystère" << endl;
    
    			while (getline(flux, ligneDico)) { //On lit une ligne complète
    
    				cptMot++;
    			}
    
    			srand(time(nullptr));
    			ligneMot = rand() %cptMot+1;
    			flux.seekg(0, ios::beg); // lire le debut du fichier c'est utile ?????
    			cout<< "boucle" << ligneDico;
    			while (getline(flux, ligneDico)) { //On lit une ligne complète
    
    						cptChoix++;
    						cout << cptChoix << ligneMot<< endl;
    						if(cptChoix == ligneMot){
    							cout<< ligneMot;
    							break;
    						}
    
    				}
    
    
    			return ligneDico;
    }
    

    Voici ce que le compilateur dit

    error: use of deleted function 'std::basic_ifstream<_CharT, _Traits>::basic_ifstream(const std::basic_ifstream<_CharT, _Traits>&) [with _CharT = char; _Traits = std::char_traits<char>]'

    Et mon header est simple il n'y a rien dedans a part la fonction voici quand même le code du header

    #ifndef MOTMUSTERE_H_
    #define MOTMUSTERE_H_
    
    #include<iostream>
    #include<time.h>
    #include <fstream>
    #include <string>
    
    
    
    std::string choixDuMot(std::ifstream flux);
    
    
    
    
    #endif /* MOTMUSTERE_H_ */
    

    Avez vous un idée?

    J'ai aussi l'impression que la 2eme boucle ou je lis ligne par ligne ne fonctionne pas! Je comprends pas pourquoi non plus !! 

    • Partager sur Facebook
    • Partager sur Twitter
      21 août 2019 à 12:19:44

      Salut ! Passe ton ifstream par référence, avec &
      • Partager sur Facebook
      • Partager sur Twitter

      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

        21 août 2019 à 12:40:52

        Salut,

        Don_raftapss a écrit:

        Salut, je commence à apprendre le c++ et je remarque que les chose ne fonctionne pas comme en C.

        Première chose le type de retour string. Ma fonction créer renvoie un type string mais le compilateur il veut pas... Je comprends pas trop pourquoi.

        Sur ce point là, les choses fonctionnent exactement comme en C !! le compilateur traite le code un peu à la manière dont tu lis un livre : de la première page à la dernière.  Et, tout comme toi, qui ne sais pas ce qui se passe à la page 12 quand tu es occupé à lire la page 10, le compilateur ne "connait" que ce qu'il a déjà croisé dans les lignes précédentes : si, arrivé à la ligne 11, il rencontre l'appel à  une fonction dont il n'apprend l'existence qu'à la ligne 21, il ne va pas être content ;) 

        Mais, comme tu  as un fichier d'en-tête (je reviendrai dessus juste un peu plus tard ;) ), et qu'il est correctement inclus dans ton fichier d'implémentation, le problème n'est en réalité pas là : le problème, c'est que, tout comme en C, la transmission des paramètres se fait par copie, si on ne donne aucune indication contraire.

        Manque de bol, la classe std::ifstream (et la classe std::ofstream d'ailleurs) ne peut pas être copiée, ce qui est normal, vu qu'elle intervient dans une hiérarchie de classes, et qu'elle a donc sémantique d'entité.

        D'ailleurs, si tu faisais un peu attention aux messages émis par le compilateur, tu te rendrais compte qu'il t'émet un message proche de

        main.cpp:<ligne>:<colonne> : error : use of deleted function 'std::basic_ifstream</*... */
            motMyst= choixDuMot(FluxLecturefichier); // ligne fausse

        (car il faut savior que la classe std::ifstream n'est jamais qu'un alias de type sur la classe std::basic_istream ;) ).

        La solution est toute simple : il ne faut pas transmettre cette instance par copie, mais le faire par référence:   Corrige le prototype (dans le fichier d'en-tête et dans le fichier d'implémentation) pour lui donner la forme de

        std::string choixDuMot(std::ifstream & flux);

        et ton problème sera résolu: C'est fou comme une simple petite esperluette peut changer les choses, non ?

        Retour sur le fichier d'en-tête

        Tout comme en C, on va essayer de limiter au maximum les fichiers d'en-tête que l'on inclut dans nos propres fichiers d'en-tête, de manière à "accélérer" le travail du préprocesseur.

        En effet, le contenu d'un fichier d'en-tête a une sérieuse tendance à avoir un comportement presque viral, vu qu'il peut être inclut dans n'importe quel fichier :'(

        Les fichiers <time.h> et <iostream> n'ont donc absolument aucune raison d'être inclus dans ton fichier d'en-tête : inclus les -- uniquement si tu en as besoin -- directement dans le fichier d'implémentation ;)

        Enfin, l'inclusion de fichier d'en-tête comme <iostream> ou <fstream> rajoute à chaque fois un bonne trentaine de millier de lignes à ton code; si bien qu'on préférera de loin ne les inlcure que ... dans les fichiers qui en ont réellement besoin ;)

        Lorsqu'il "suffit" de disposer d'une déclaration anticipée, par exemple, pour pouvoir déclarer une fonction qui prend (une référence sur) une instance de ifstream comme paramètre dans un fichier d'en-tête, on préférera inclure le fichier <iosfwd>, qui ne contient que les déclarations anticipées de toutes les classes dérivée de basic_istream ;)

        Au final, tu obtiendrais donc un fichier d'en-tête proche de

        #ifndef MOTMUSTERE_H_
        #define MOTMUSTERE_H_
        /* pour la déclaration anticipée de ifstream */
        #inclde <iosfwd>
        /* pour connaitre la classe std::string */
        #include <string>
         
         
         
        std::string choixDuMot(std::ifstream & flux);
         
         
         
         
        #endif /* MOTMUSTERE_H_ */

        et le fichier d'implémentation proche de

        #include "motMustere.h"
        #include <ifstream>
        #include <iostream>
        /*  et tout le reste */

        Enfin, au lieu de passer ton temps à lire le fichier pour choisir le mot, ce qui va prendre un temps bête (en plus de poser de sériseux problèmes), vu que la lecture de fichier à partir d'un disque dur est l'un des processus les plus lents qui existent, pourquoi ne lirais tu pas, une bonne fois pour toutes, l'ensemble des mot que le fichier contient pour les placer dans une collection qui te permettrait d'y accéder beaucoup plus facilement (un std::vector, par exemple) ?

        Et pour vraiment conclure cette intervention, une remarque essentielle : on n'utilise JAMAIS la directive using namespace std;. Cette intervention étant déjà largement assez longue, et les raisons ayant été données à de multiples reprises, je vais te laisser faire une recherche sur ce sujet sur ce forum ;)

        • Partager sur Facebook
        • Partager sur Twitter
        Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
          21 août 2019 à 13:00:38

          Merci de vos réponse je comprends un peu mieux. Vilaine esperluette :D. Je vais faire sans la directive j'avais lu quelque part aussi. Par contre quel genre de directive est utile du coups?
          • Partager sur Facebook
          • Partager sur Twitter
            21 août 2019 à 14:37:01

            Don_raftapss a écrit:

            Par contre quel genre de directive est utile du coups?

            Aucune, j'utilise systématiquement ce que l'on appelle les "noms pleinement qualifiés" : std::cout, std::cin, std::string, std::ifstream, ... :)

            • Partager sur Facebook
            • Partager sur Twitter
            Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
              23 août 2019 à 9:14:33

              Ta fonction choixDuMot est scandaleuse. Tu traverses le fichier une fois pour obtenir le nombre de ligne puis tu le traverses à nouveau. Ce qui en plus d'être particulièrement stupide provoque une race condition.

              Traverse le fichier une seule fois et remplie un vector. Ensuite tu remvoies un mot de 0 à N-1 de ce vector. Aussi simple que ça.

              -
              Edité par markand 23 août 2019 à 9:15:09

              • Partager sur Facebook
              • Partager sur Twitter

              git is great because Linus did it, mercurial is better because he didn't.

                23 août 2019 à 10:21:19


                Koala01 a écrit:

                Don_raftapss a écrit:

                Par contre quel genre de directive est utile du coups?

                Aucune, j'utilise systématiquement ce que l'on appelle les "noms pleinement qualifiés" : std::cout, std::cin, std::string, std::ifstream, ... :)

                J'utilise aussi quasiment systématiquement les noms pleinement qualifiés, mais il arrive parfois qu'il soit utile d'utiliser une directive using, pour plus de de souplesse. L'exemple qui me vient à l'esprit est un cas de portabilité: J'utilise deux compilateurs Visual C++ 2017/2019 et MinGW gcc 7.x. Sur Visual C++ j'ai accès à std::filesystem, sur MinGW gcc 7.x, je dois utiliser boost::filesystem, car std::filesystem n'est pas disponible sur les versions que j'utilise. Je me suis donc créé un fichier d'en-tête qui en fonction d'un define va me créer un namespace (fs pour faire court), qui sera soit un alias de boost::filesystem, soit un alias de std::filesystem. Ainsi, dans le reste de mon code, je qualifie avec mon alias, et le code compile quelque soit le compilateur que j'utilise.

                #ifndef DBPFBASE_FILESYSTEM_HPP_HEADER_INCLUDED
                #define DBPFBASE_FILESYSTEM_HPP_HEADER_INCLUDED
                //==============================================================================
                
                //==============================================================================
                #if defined(DBPF_USE_STD_FILESYSTEM)
                /*
                    Visual C++
                */
                //==============================================================================
                #include<filesystem>
                #include<fstream>
                //==============================================================================
                namespace dbpf { // Mon namespace privé
                namespace fs { // Le fameux namespace fs
                //==============================================================================
                using namespace std; //  Pas de probleme ici la portee est limitee au namespace dbpf::fs
                using namespace std::experimental::filesystem::v1;
                //==============================================================================
                inline void overwrite(fs::path const& src, fs::path const& dst) {
                	fs::copy_file(src, dst, fs::copy_options::overwrite_existing);
                }
                //==============================================================================
                }} // namespace dbpf::fs
                //==============================================================================
                #else   /* Pas de support de std::filesystem on utilise boost::filesystem à la place */ 
                //==============================================================================
                #include<boost/filesystem.hpp>
                #include<boost/filesystem/fstream.hpp>
                //==============================================================================
                namespace dbpf{ // Mon espace prive
                namespace fs {  // Le sous-namespace
                //==============================================================================
                using namespace boost::filesystem;     // pas de soucis je suis en portee restreinte
                using copy_options = fs::copy_option;  // un alias de type, car ils n'ont pas le même nom
                //==============================================================================
                inline void overwrite(fs::path const& src, fs::path const& dst) {
                    fs::copy_file(src, dst, fs::copy_option::overwrite_if_exists);
                }
                //==============================================================================
                }}  // namespace dbpf::fs
                //==============================================================================
                #endif // defined(DBPF_USE_STD_FILESYSTEM)
                //==============================================================================
                /* Déclarations communes pour tout les compilateurs */
                //==============================================================================
                #include<vector>
                //==============================================================================
                namespace dbpf { namespace fs {
                //==============================================================================
                using FileList = std::vector<path>; // une liste de fichiers/chemins
                //==============================================================================
                inline bool isFileWithExt(path const & f){
                    return is_regular_file(f) && f.has_extension();
                }
                //==============================================================================
                }} // namespace dbpf::fs
                //==============================================================================
                #endif // DBPFBASE_FILESYSTEM_HPP_HEADER_INCLUDED
                //==============================================================================
                
                • Partager sur Facebook
                • Partager sur Twitter
                Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                  23 août 2019 à 12:57:02

                  markand a écrit:

                  Ta fonction choixDuMot est scandaleuse. Tu traverses le fichier une fois pour obtenir le nombre de ligne puis tu le traverses à nouveau. Ce qui en plus d'être particulièrement stupide provoque une race condition.

                  Traverse le fichier une seule fois et remplie un vector. Ensuite tu remvoies un mot de 0 à N-1 de ce vector. Aussi simple que ça.

                  -
                  Edité par markand il y a environ 3 heures

                  En effet je testais des trucs c'est tout. Pour finir j'ai fais avec un vector<string>. Par contre j'ai corrigé l'exercie des autres (cotation openclassroom). Et plein de gens parcours le fichier plusieurs fois. En fait je n'ai pas vu un seul exercice qui le faisait. 

                  int21h a écrit:


                  Koala01 a écrit:

                  Don_raftapss a écrit:

                  Par contre quel genre de directive est utile du coups?

                  Aucune, j'utilise systématiquement ce que l'on appelle les "noms pleinement qualifiés" : std::coutstd::cinstd::stringstd::ifstream, ... :)

                  J'utilise aussi quasiment systématiquement les noms pleinement qualifiés, mais il arrive parfois qu'il soit utile d'utiliser une directive using, pour plus de de souplesse. L'exemple qui me vient à l'esprit est un cas de portabilité: J'utilise deux compilateurs Visual C++ 2017/2019 et MinGW gcc 7.x. Sur Visual C++ j'ai accès à std::filesystem, sur MinGW gcc 7.x, je dois utiliser boost::filesystem, car std::filesystem n'est pas disponible sur les versions que j'utilise. Je me suis donc créé un fichier d'en-tête qui en fonction d'un define va me créer un namespace (fs pour faire court), qui sera soit un alias de boost::filesystem, soit un alias de std::filesystem. Ainsi, dans le reste de mon code, je qualifie avec mon alias, et le code compile quelque soit le compilateur que j'utilise.

                  #ifndef DBPFBASE_FILESYSTEM_HPP_HEADER_INCLUDED
                  #define DBPFBASE_FILESYSTEM_HPP_HEADER_INCLUDED
                  //==============================================================================
                  
                  //==============================================================================
                  #if defined(DBPF_USE_STD_FILESYSTEM)
                  /*
                      Visual C++
                  */
                  //==============================================================================
                  #include<filesystem>
                  #include<fstream>
                  //==============================================================================
                  namespace dbpf { // Mon namespace privé
                  namespace fs { // Le fameux namespace fs
                  //==============================================================================
                  using namespace std; //  Pas de probleme ici la portee est limitee au namespace dbpf::fs
                  using namespace std::experimental::filesystem::v1;
                  //==============================================================================
                  inline void overwrite(fs::path const& src, fs::path const& dst) {
                  	fs::copy_file(src, dst, fs::copy_options::overwrite_existing);
                  }
                  //==============================================================================
                  }} // namespace dbpf::fs
                  //==============================================================================
                  #else   /* Pas de support de std::filesystem on utilise boost::filesystem à la place */ 
                  //==============================================================================
                  #include<boost/filesystem.hpp>
                  #include<boost/filesystem/fstream.hpp>
                  //==============================================================================
                  namespace dbpf{ // Mon espace prive
                  namespace fs {  // Le sous-namespace
                  //==============================================================================
                  using namespace boost::filesystem;     // pas de soucis je suis en portee restreinte
                  using copy_options = fs::copy_option;  // un alias de type, car ils n'ont pas le même nom
                  //==============================================================================
                  inline void overwrite(fs::path const& src, fs::path const& dst) {
                      fs::copy_file(src, dst, fs::copy_option::overwrite_if_exists);
                  }
                  //==============================================================================
                  }}  // namespace dbpf::fs
                  //==============================================================================
                  #endif // defined(DBPF_USE_STD_FILESYSTEM)
                  //==============================================================================
                  /* Déclarations communes pour tout les compilateurs */
                  //==============================================================================
                  #include<vector>
                  //==============================================================================
                  namespace dbpf { namespace fs {
                  //==============================================================================
                  using FileList = std::vector<path>; // une liste de fichiers/chemins
                  //==============================================================================
                  inline bool isFileWithExt(path const & f){
                      return is_regular_file(f) && f.has_extension();
                  }
                  //==============================================================================
                  }} // namespace dbpf::fs
                  //==============================================================================
                  #endif // DBPFBASE_FILESYSTEM_HPP_HEADER_INCLUDED
                  //==============================================================================
                  

                  J'y aurais jamais pensé merci pour ton idée qui est magnifique

                  -
                  Edité par Don_raftapss 23 août 2019 à 12:59:58

                  • Partager sur Facebook
                  • Partager sur Twitter
                    23 août 2019 à 17:14:31

                    > En effet je testais des trucs c'est tout. Pour finir j'ai fais avec un vector<string>. Par contre j'ai corrigé l'exercie des autres (cotation openclassroom). Et plein de gens parcours le fichier plusieurs fois. En fait je n'ai pas vu un seul exercice qui le faisait.

                    Parce que les autres sont aussi des débutants qui suivent ce cours tellement mal fichu qu'après lecture il ne vient pas à l'idée de ne faire qu'un seul parcours et tout mettre dans un std::vector.

                    Sinon, comme cela n'a pas été dit: n'utilise pas rand/srand qui sont déconseillés, mais les classes de l'en-tête <random> comme uniform_int_distribution.

                    -
                    Edité par jo_link_noir 23 août 2019 à 17:14:58

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Problème de compréhension

                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                    • Editeur
                    • Markdown