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 :

probleme avec les références


Sujet :

C++

  1. #1
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut probleme avec les références
    Bonjour,
    Je suis occupé d'écrire une classe
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Class abcd{
    	private:
    		char* nom;
    		int r, v, b;
    	public:
    		...// les getter setter,...
    		void Save(std::ofstream&) const;
     
    }
    et j'essayes de faire une methode save
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void abcd::Save(ofstream &fichier) const{
    	fichier.write(getNom(), sizeof(getNom()));
    	fichier.write((char*) &getRouge(), sizeof(getRouge())); // cette ligne pause probleme	
    }
    j'ai également tenté
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    fichier.write((char*) &(getRouge()), sizeof(getRouge()));
    mais cela ne fonctionnes pas je suis obligé de décrarer une variable tmp et puis d'en récupérer l'adresse
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int tmp = getRouge();
    	fichier.write((char*) &tmp, sizeof(getRouge()));
    Pourquoi?
    merci d'avance

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 627
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 627
    Points : 10 548
    Points
    10 548
    Par défaut
    Citation Envoyé par Sparky95 Voir le message
    Pourquoi?
    À vue de nez, cela semble logique ... mais je peux me tromper.

    Lorsque tu appelles ton accesseur getRouge(), le retour va être stocké dans une variable temporaire (le RVO ne fonctionne pas parce que tu ne stockes pas ce retour)
    Et tu prends l'adresse de cette variable temporaire Quand cette variable va-t-elle être détruite ? juste après l'appel de ton accesseur getRouge() ? après l'appel de la fonction write ?

    Avec une vraie variable, on sait qu'elle sera détruite à la fin du bloc

  3. #3
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    Je ne sais pas j'aurais dis apres la fin de l'execution de la ligne donc getRouge retourn la valeur qui est disponible jusqu'a la fin de l'execution de la ligne donc jusqu'a la fin du write dans ce cas si

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 113
    Points : 32 958
    Points
    32 958
    Billets dans le blog
    4
    Par défaut
    getRouge devrait fonctionner, effectivement il y a une variable temporaire qui sera détruite après l'appel au write. Vu que c'est un int, ça passe jusque là. Reste ensuite le cast brutal en char*, lui peut ne pas passer et faire des choses bizarres, faut tester.
    Par contre fichier.write(getNom(), sizeof(getNom())); ne va certainement pas écrire le contenu de nom ne serait-ce que parce que, à moins d'avoir un nom composer de 1 caractère à la limite, sizeof(getNom()) ne retourne certainement pas ce qui est espéré..
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    Le truc est que la méthode demande un char* =>ostream& write (const char* s, streamsize n);.

    Donc sauf erreur de ma part je suis obligé de faire un casting.
    Quand au fichier.write((char*)&getRouge(), sizeof(getRouge())); il me mets cette erreur lorsque j'essayes de compiler.

    Nom : download.png
Affichages : 242
Taille : 49,0 Ko

    idem si je rajoute les parenthèses &(getRouge())

  6. #6
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 678
    Points
    13 678
    Billets dans le blog
    1
    Par défaut
    Pourquoi faire des char* en C++ alors que tu as std::string ?

    Pourquoi utiliser des getters à l'intérieur d'une fonction membre quand tu pourrais directement accéder à la donnée membre ?

    Pourquoi ne pas nous montrer le corps de getRouge() ? Je présume qu'elle renvoie r, qui aurait peut-être dû s'appeler rouge du coup ?

    Enfin, pourquoi ne pas utiliser l'opérateur << de ton ofstream pour écrire dans le fichier et ainsi te simplifier grandement la vie ? Voir http://www.cplusplus.com/doc/tutorial/files/

  7. #7
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    Consignes scolaire
    on ne peux pas utiliser de string
    je l'ai appelé r mais oui c'est rouge et je passais pas les getter et setter car il est conseillé de faire ça dans les consignes.
    Les profs nous ont dis qu'étant donné que les valeurs retournés pouvaient être modifiés
    Exemple pour une personne nom retourne nom puis d'un coup on veut changer et l'on retournes nom et prénom il était mieux de toujours passer par les getter et setters
    Il est également demandé qu'on fassent une méthode save et load avec write et read respectivement dedant du coup je ne pense pas que les opérateurs << et >> puissent être utilisés

  8. #8
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 678
    Points
    13 678
    Billets dans le blog
    1
    Par défaut
    "On ne peut pas utiliser std::string"... J'ai presque envie que tu me donnes le mail de ton prof pour en discuter avec lui

    C'est vrai qu'il est toujours mieux d'avoir des getters et des setters, mais c'est surtout vrai depuis l'extérieur de la classe. Ca évite de casser tout le code utilisant ta classe quand tu changes l'intérieur de la classe. Mais impacter l'intérieur d'une classe quand tu changes l'intérieur d'une classe n'est pas illogique.

    "Il est également demandé qu'on fassent une méthode save et load avec write et read respectivement dedant du coup je ne pense pas que les opérateurs << et >> puissent être utilisés".... Il va vraiment falloir qu'on parle avec tes profs, histoire de leur expliquer la différence entre C et C++ Bon OK, va falloir faire avec. Dans ce cas, n'oublie pas l'intérêt d'une variable locale :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    type rouge = getRouge();
    std::size_t taille = ??;
    f.write(rouge, taille);
    Et puisque tu es obligé d'utiliser char*, répond à la question : que vaut sizeof(char*) ?

  9. #9
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    et bien en fait on ne peut pas utiliser la partie string "purement pédagogiquement" ^^

    mon but était d'écrire en une ligne le write du coup je l'ai changé comme tu m'avais conseillé fichier.write((char*)&r, sizeof(r));Par contre j'étais justement occupé de me pauser la question et je pense que ton dernier msg y fait référence le sizeof(r) est-il correct?
    Étant donné que j'enregistre dans le fichier un size char* et que je lui dis que ça fait la taille d'un int?
    ou ça peut importe étant donné que c'est moi qui décide de la taille que je donnes?
    Je me demande cela pour la partie load car j'aurais tendance à écrire fichier.read((char*)tmp, sizeof(tmp));
    Par rapport au nom je m'étais trompé et j'ai changé le sizeof(getNom()) par strlen(getNom()) + 1

  10. #10
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 678
    Points
    13 678
    Billets dans le blog
    1
    Par défaut
    Il y a en effet un piège, pour ça que j'en parle

    Exécute ce code et regarde ce que ça donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <cstring>
    #include <iostream>
     
    int main() {
    	const char* nom = "jean-jack"; // 9 lettres + '\0'
    	std::cout << sizeof(nom) << std::endl;
    	std::cout << sizeof(char*) << std::endl;
    	std::cout << std::strlen(nom) << std::endl;
    	std::cout << std::strlen(nom) + 1 << std::endl;
     
    	int rouge = 123;
    	std::cout << sizeof(rouge) << std::endl;
    	std::cout << sizeof(int) << std::endl;
    }
    Allez je suis sympa je te donne le résultat ça ira plus vite

    8
    8
    9
    10
    4
    4

    PS : voici à quoi tu aurais pû arriver en faisant vraiment du C++

    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
    #include <fstream>
     
    class abcd {
    public:
    	abcd(int rouge, int vert, int bleu, const std::string& nom) :
    			rouge(rouge), vert(vert), bleu(bleu), nom(nom) {
    	}
     
    	void save(std::ofstream& of) {
    		of << rouge << vert << bleu << nom;
    	}
     
    private:
    	int rouge, vert, bleu;
    	std::string nom;
    };
     
    int main() {
    	std::ofstream f;
    	f.open("output.txt");
    	f << "Writing this to a file.\n";
     
    	abcd instance{255, 15, 89, "hello"};
    	instance.save(f);
     
    	f.close();
    }

  11. #11
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    hehe ce serrait trop beau

    seulement les profs aimes bien nous les compliqués
    du coup au final j'ai fais d'apres ce que tu viens de me montrer ceci
    Code C++ : 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
     
    void Couleur::Save(ofstream &fichier) const{
    	int tmp;
    	if(getNom()){
    		tmp = strlen(getNom()) + 1;
    		fichier.write((char*) &tmp, sizeof(char*));
    		fichier.write(getNom(), tmp);
    	}else{
    		tmp = 0;
    		fichier.write((char*)&tmp, sizeof(char*));
    	}
     
    	fichier.write((char*)&r, sizeof(char*));
    	fichier.write((char*)&v, sizeof(char*));
    	fichier.write((char*)&b, sizeof(char*));
    }
     
    void Couleur::Load(ifstream &fichier){
    	char tmpNom[50];
    	int tmp;
     
    	fichier.read((char*)&tmp, sizeof(char*));
    	if(tmp){
    		fichier.read(tmpNom, tmp);
    		setNom(tmpNom);
    	}
    	fichier.read((char*)&tmp, sizeof(char*)); 
    	setRouge(tmp);
    	fichier.read((char*)&tmp, sizeof(char*));
    	setVert(tmp);
    	fichier.read((char*)&tmp, sizeof(char*));
    	setBleu(tmp);
    }
    d'accord ou tu pense que je devrais faire ça autrement encore?
    élément pas encore testé j'essaye de le faire via la logique yet

  12. #12
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Il y a un problème dans l'utilisation de sizeof pour r, v, b. Ces variables ne sont pas de type char*, donc la taille écrite ou lue ne sera pas la bonne.

    fichier.write((char*)&r, sizeof(r)); est la bonne manière, sauf pour les pointeurs comme le fait remarquer @Bktero, car ce n'est pas la valeur du pointeur qui importe, mais la valeur pointée.

    C'est facile de faire une erreur sur les tailles, et utiliser quelques fonctions intermédiaire pourrait éliminer la plupart des erreurs.

    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 <type_traits>
     
    // valide pour tous les types d'entiers ou booléen (bool, char, short, int, long, ...)
    // au pire, faire plusieurs surcharges
    template<class T>
    std::enable_if_t<std::is_integral_v<T>> write(std::ofstream& out, T const& x)
    {
      out.write(reinterpret_cast<char const*>(&x), sizeof(x));
    }
     
    void write(std::ofstream& out, char const* s)
    {
      if (s) {
        int size = strlen(s);
        write(out, size);
        out.write(s, size);
      }
      else {
        write(out, int(0));
      }
    }
     
     
    void Couleur::Save(ofstream &fichier) const{
    	write(fichier, getNom());
     	write(fichier, r);
     	write(fichier, v);
     	write(fichier, b);
    }
    Ce qui simplifie beaucoup l'utilisation et réduit les erreurs. La même chose peut être fait avec la lecture.

  13. #13
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    merci beaucoup

  14. #14
    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
    Citation Envoyé par Bktero Voir le message
    "On ne peut pas utiliser std::string"... J'ai presque envie que tu me donnes le mail de ton prof pour en discuter avec lui

    <snip>

    "Il est également demandé qu'on fassent une méthode save et load avec write et read respectivement dedant du coup je ne pense pas que les opérateurs << et >> puissent être utilisés".... Il va vraiment falloir qu'on parle avec tes profs, histoire de leur expliquer la différence entre C et C++ ?
    J'ai compris ça comme "on cherche à faire une sérialisation binaire, pas un fichier texte". Qui est un motif valable à mon goût, ne serait-ce que pour la valeur pédagogique d'apprendre que les auteurs des normes C++ haïssent ce concept (il n'y a qu'à voir la spécification des RNGs du C++11 pour en avoir confirmation).
    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.

  15. #15
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par Bktero Voir le message
    "On ne peut pas utiliser std::string"... J'ai presque envie que tu me donnes le mail de ton prof pour en discuter avec lui
    Oh oui!!! Je veux son E-mail (on peut me le donner par MP, au besoin)!!!

    Mais je vous préviens : après avoir reçu mon mail, il risque de se mettre en dépression jusqu'à la fin de l'année

    Citation Envoyé par Médinoc Voir le message
    J'ai compris ça comme "on cherche à faire une sérialisation binaire, pas un fichier texte". Qui est un motif valable à mon goût, ne serait-ce que pour la valeur pédagogique d'apprendre que les auteurs des normes C++ haïssent ce concept (il n'y a qu'à voir la spécification des RNGs du C++11 pour en avoir confirmation).
    Et que penser d'un simple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void Couleur::Save(ofstream &fichier) const{ // partons du principe que fichier est ouvert en binaire
        fichier.write(nom.size(), sizeof(size_t));
        fichier.write(nom.data(), nom.size());
        /* la suite */
    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

  16. #16
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Et que penser d'un simple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void Couleur::Save(ofstream &fichier) const{ // partons du principe que fichier est ouvert en binaire
        fichier.write(nom.size(), sizeof(size_t));
        fichier.write(nom.data(), nom.size());
        /* la suite */
    étant donné que le prototype de la méthode est ostream& write (const char* s, streamsize n); cela n'ira pas sauf erreur de ma part
    car les data sont des int

  17. #17
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par Sparky95 Voir le message
    étant donné que le prototype de la méthode est ostream& write (const char* s, streamsize n); cela n'ira pas sauf erreur de ma part
    car les data sont des int
    Vérifie bien le prototype de la fonction membre data... c'est bel et bien un CharT* qu'elle renvoie, et donc un char * (pour std::string)

    Jusqu'à il y a peu, c'était un const CharT*, ce qui faisait -- effectivement -- gueuler le compilateur suite à l'impossibilité de convertir un const char * et char *, mais ce soucis a été résolu en C++17

    Après, il reste, effectivement le "problème" des chaines "multbytes" (std::wstring, std::u16string, std::u32string), dont la fonction data renverra -- effectivement -- respectivement un wchar_t *, un char16_t * ou un char32_t * selon le cas...

    Et encore, ce n'est qu'un faux problème, car la norme défini clairement la taille du type char comme étant "l'unité" de mesure de taille de tous les autres types (primitifs ou non), ainsi que le fait qu'il est légal de convertir n'importe quelle donnée (qu'il s'agisse d'un type primitif ou non) en un tableau de char de taille équivalente, et de refaire la conversion inverse par la suite, sans risque de perte de données.

    Dans le pire des cas, si l'on utilise une de ces spécialisation de std::basic_string, et que l'on ignore même de quel type il s'agit effectivement, nous pouvons donc modifier le code pour lui donner une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void Couleur::Save(ofstream &fichier) const{ // partons du principe que fichier est ouvert en binaire
        size_t charSize{sizeof nom::value_type)};
        fichier.write(nom.size()*charSize, sizeof(size_t));
        fichier.write(static_cast<char * >(nom.data()), nom.size()* charSize);
    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

  18. #18
    Invité
    Invité(e)
    Par défaut
    Bonsoir,

    Citation Envoyé par koala01 Voir le message
    Vérifie bien le prototype de la fonction membre data... c'est bel et bien un CharT* qu'elle renvoie, et donc un char * (pour std::string)
    Et donc que penses-tu que ça donne avec les lignes fichier.write(nom.size(), sizeof(size_t)); / fichier.write(nom.size()*charSize, sizeof(size_t)); ?

    Et si l'on veut vraiment gérer les std::(w/u16/u32)string, le static_cast static_cast<char * >(nom.data()) ne passera pas.

    Note que sizeof(nom::value_type) est également invalide sizeof(decltype(nom)::value_type), et utiliser son size_type ne fera pas de mal non plus.

    Sinon inutile de se casser la tête, la réponse a déjà été donnée.

  19. #19
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par Winjerome Voir le message
    Bonsoir,


    Et donc que penses-tu que ça donne avec les lignes fichier.write(nom.size(), sizeof(size_t)); / fichier.write(nom.size()*charSize, sizeof(size_t)); ?
    Oupps, en relisant le code, je me rend compte que j'étais particulièrement fatigué quand je l'ai écrit, au moins pour l'écriture de la taille.

    Au temps pour moi, la valeur correspondant à la taille de la chaine doit être une L value et c'est bel et bien à chaque fois un reinterpret_cast qu'il faut utiliser.

    Mais, oui, et non seulement je le pense clairement que l'utilisation de la fonction data suffit (car c'est de cela qu'il s'agit), mais j'en suis sur au point de pouvoir le prouver, aux erreurs d'attention près.

    Comme je l'ai dit plus haut, la fonction data renvoyait un const CharT * jusqu'à il y a peu, ce qui correspondait -- pour std::string, qui n'est qu'un alias de std::basic_string<char> -- à un const char * et qui aurait effectivement fait gueuler le compilateur suite à la perte de la constance entre un const char * (renvoyé par la fonction data() et le prototype de la fonction write qui s'attend à obtenir un char * comme premier paramètre.

    C'était d'autant plus idiot que la fonction membre c_str() renvoie elle aussi un const CharT * et que, du coup, il y avait deux fonctions qui permettaient d'obtenir exactement la même chose au '\0' final près.

    Comme l'indique si bien le lien que j'ai fourni plus haut, les choses ont changé en C++17. C'est donc très récent, je te l'accorde, mais c'est la norme que j'utilise, et je ne me gène donc pas pour en profiter

    Ensuite, il est vrai que tu pourrais éprouver des problèmes si tu décidais d'utiliser une norme plus ancienne, et que tu devrais donc faire un const_cast pour virer ce CV qualilfer qui fout la merde.

    Voici un code strictement minimal qui ouvre un fichier binaire en écriture et qui y envoie successivement la taille d'une chaine de caractères et son contenu ("hello world").
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #include <fstream>
    #include <string>
    int main(){
        std::ofstream ofs{"Data.dat", std::ios_base::binary};
        std::string str{"Hello world"};
        auto size = str.size();
        ofs.write(reinterpret_cast<char*>(&size), sizeof(size_t));
        ofs.write(str.data(), str.size());
        return 0;
    }
    Ce code compile sans le moindre avertissement et, après exécution, nous obtenons bel et bien un fichier binaire, dont voici le contenu présenté par un éditeur hexadécimal:
    Nom : Capture d’écran du 2019-01-11 17-25-25.png
Affichages : 201
Taille : 40,6 Ko

    Si tu y regardes correctement, tu te rend compte que les huit premiers bytes (0B 00 00 00 00 00 00 00 seront interprété comme un entier 32 bits dont la valeur est égale à 11 (en version signée comme en version non signée), et que les onze byte suivants corresponde bel et bien à la valeur de la chaine de caractères

    Et si l'on veut vraiment gérer les std::(w/u16/u32)string, le static_cast static_cast<char * >(nom.data()) ne passera pas.
    De fait, ce n'est pas static_cast mais reinterpret_cast que j'aurais du utiliser. Mea Culpa.

    Mais le principe reste tout à fait valable
    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

  20. #20
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    Hihi merci
    mais petit rappel c'est la rubrique débutant et même si j'en apprends par la même occasion pas mal vous partez parfois dans des délires que je n'arrives plus a suivre :p
    Toute ce que je voulais c'est pouvoir faire un write basic de quelques char et int pour le cours sans partir dans une généralisation super top qui je dois l'avouer serrait mieux mais qui est encore un peu haut lvl pour mon niveau actuel ^^
    Du coup je relirai attentivement c'est explications dans 6 mois en espérant en comprendre d'avantage
    en tout cas merci pour le boulot que vous avez fournis
    Par rapport à l'email du prof la veux tu vraiment?
    Car si c'est le cas (on ne s'est jamais parlé) je tiens à avoir mes points hahahah

    Quand au compilateur fournis par le cours c'est
    g++ (GCC) 5.4.0

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. problemes avec les références
    Par saeba357 dans le forum Langage
    Réponses: 2
    Dernier message: 14/05/2009, 15h52
  2. Help!! Probleme avec les dates sur SQL SERVER
    Par Nadaa dans le forum MS SQL Server
    Réponses: 16
    Dernier message: 03/08/2006, 17h55
  3. PROBLEME AVEC LES REQUETES IS NULL / NOT EXISTS
    Par sylvaine dans le forum Langage SQL
    Réponses: 5
    Dernier message: 04/06/2004, 14h26
  4. Problem avec les *.AVI sur les panels
    Par NaDiA_SoFt dans le forum C++Builder
    Réponses: 3
    Dernier message: 31/08/2003, 23h50
  5. probleme avec les processus
    Par saidi dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 05/02/2003, 01h18

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