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 :

A propos de std::ostrstream


Sujet :

SL & STL C++

  1. #1
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut A propos de std::ostrstream
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	std::ostrstream ss;
    	ss << '(' << __FILE__ << ", " << __LINE__ << ')' << std::endl;
    	std::string s(ss.str());
    Voici un simple code. Il apparait que dans "s" j'obtiens plein de caractères "parasites" derrière le retour de ligne. N'y a-t-il donc pas un '\0' à la fin comme dans tout C string "normal" ?

  2. #2
    Membre émérite
    Avatar de Spout
    Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    904
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Février 2007
    Messages : 904
    Par défaut
    Salut,

    Effectivement, c'est étonnant.
    Cependant j'ai une question: est-ce lors de l'impression de la chaîne (affichage à l'écran, dans un fichier, ...), où est-ce seulement la représentation que t'en donne le debuggeur qui fait apparaitre ces fameux caractères?

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    De mémoire, ostrstream demande des std::ends en fin de chaîne. Et il demande aussi de gérer des freeze de buffer. Il y a des cas où il peut être plus performant que ostringstream, mais ce n'est pas le cas ici (il faudrait lui passer un buffer pré-alloué).

    Es-tu certain de ne pas vouloir utiliser ostringstream, qui est bien plus simple d'emploi ?
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #4
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Oui, sans doute...
    Merci.
    C'est un foutoir ces stream je trouve... Quand utiliser lequel, où et pourquoi ?

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

    Informations professionnelles :
    Activité : aucun

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

    C'est pourtant simple... il faut utiliser
    • ifstream si tu veux un fichier qui sera tout le temps lu
    • ofstream si tu veux un fichier qui sera tout le temps écrit
    • fstream si tu veux pouvoir passer d'un fichier en lecture à un fichier en écriture (et inversément)
    • istringstream si tu veux convertir une chaine de caractères en n'importe quoi
    • ostringstream si tu veux convertir n'importe quoi en chaine de caractères
    • stringstream si tu veux pouvoir effectuer des conversions dans les deux sens
    • istream si tu veux utiliser n'importe quel flux en lecture (qui peut être un fichier, un flux de conversion ou un flux d'entrée standard)
    • ostream si tu veux utiliser n'importe quel flux en écriture (qui peut être un fichier, un flux de conversion ou un flux de sortie standard)
    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

  6. #6
    Membre expérimenté Avatar de g0up1l
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    341
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 341
    Par défaut
    Citation Envoyé par camboui Voir le message
    C'est un foutoir ces stream je trouve... Quand utiliser lequel, où et pourquoi ?
    ha ha ouais, alors là je suis bien d'accord !
    Et de fait le std::endl, ne met pas de caractère '\0'

  7. #7
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Ok, donc je ne dois jamais utiliser ostrstream, soit.

    Pour les istream et ostream, y a-t-il des exemples d'utilisation "utiles" ?
    Par exemple, j'aimerais écrire soit dans un fichier log, soit sur la console, soit les deux, soit transférer vers une autre application, etc, le tout à la demande et dynamiquement (sans recompiler donc).
    Merci.

  8. #8
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Ce que tu veux là, ce n'est pas les flux, mais un système de log, avec notion de destination multiples. Il en existe un certain nombre, mais pas de standard de fait.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 643
    Par défaut
    La méthode "naïve" pourrait correspondre à deux variable booléennes globales, l'une servant à préciser s'il faut envoyer l'information vers la console, l'autre à préciser s'il faut l'envoyer un fichier log (en sommes, il faudrait alors prévoir de rediriger clog vers un fichier )

    Tu prévoirais alors pour tes différentes classes la surcharge de l'opérateur << 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
    friend std::ostream& oparator << (operator& ofs, const TonType& t)
    {
        ofs<<t.champs1
            <<t.champs2
            <<" une information lisible"
            <<t.champs3
            /*...*/
            <<t.chamsN;
        return ofs;
    }
    (voir dans la FAQ comment t'y prendre avec les objets polymorphes)

    Et tu t'amuserais à rajouter dans ta logique un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if(affichage_console)
        std::cout<<(*this); // ou std::cout<<variable;
    if(envoi_log)
        std::clog<<(*this); // ou std::clog<<variable;
    (ou affichage_console est le booléen demandant (ou non) l'affichage console et envoi_log celui demandant (ou non) l'envoi vers le fichier log)

    Mais tu te rendra vite compte que cette implémentation "naïve" t'obligera à écrire ce code en énormément d'endroits différents, et donc une solution plus "souple" serait:
    De surcharger l'opérateur << pour les classes qui doivent envoyer leurs information vers (la console et/ou le fichier log) et de créer un singleton proche de
    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
    32
    33
    34
    35
    36
     
    /* nous allons avoir besoin de la classe string, des entrées/sorties standard
     * et des flux de fichiers
     */
    #include <iostream>
    #include <string>
    #include <fstream>
    class Sender
    {
        public:
            static Sender& instance();
            /* permet de gérer s'il faut l'affichage console ou non */
            Sender& setConsole(bool);
            /* permet de gérer s'il faut l'envoi dans un log ou non; */
            Sender& setLog(bool l, const std::string& filename = "");
            template <class T>
            Sender& send(const T& t)
            {
                 if(console)
                     std::cout<<t<<std::endl;
                 if(log)
                     std::clog<<t<<std::endl;
                return *this;
            }
        private:
            Sender(){}
            ~Sender(){}
            static Sender* inst;
            static bool console;
            static bool log;
            /* pour être en mesure de réinitialiser clog à son comportement
             * par défaut
             */
            static std::streambuf* buf01;
            static std::ofstream* file;
    };
    L'implémentation prendrait la forme de
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
     
    #include "Sender.hpp"
    /* initialisation générale des variables statiques */
    Sender* Sender::inst = NULL;
    bool Sender::console = false;
    bool Sender::log = false;
    std::streambuf* Sender::buf01 = NULL;
    std::ofstream* Sender::file = NULL ;
    /* obtention de l'instance de notre singleton */
    Sender& Sender::instance()
    {
        if(!inst)
            inst=new Sender;
        return *inst;
    }
    /* permet de définir s'il faut un affichage console */
    Sender& Sender::setConsole(bool c)
    {
        console=c;
        return *this;
    }
    /* permet de définir s'il faut une écriture dans un fichier trace */
    Sender& Sender::setLog(bool l, const std::string& filename)
    {
        /* si l'on souhaite une écriture "log" */
        if(l)
        {
            /* si on ne précise pas de nom de fichier, c'est
             * que l'on souhaite que cela se fasse sur la sortie standard
             */
            if(filename=="")
            {
                /* si buf01 est défini, il faut récupérer le buffer d'origine
                 */
                if(buf01)
                {
                    std::clog.rdbuf(buf01);
                    buf01 = 0;
                }
                /* et détruire proprement le fichier trace s'il existe */
                delete file;
                file = NULL;
            }
            else
            {
                /* sinon, nous détruisons le fichier trace s'il existe */
                delete file;
                /* pour en ouvrir un avec le bon nom
                file = new std::ofstream(filename.c_str(),std::ios_base::app);
                /* si on n'a pas encore le buffer de sauvegarde, on 
                 * le défini en définissant le buffer de clog sur celui du 
                 * fichier, sinon, nous définissons simplement le buffer
                 * de clog sur celui du fichier
                 */
                if(!buf01)
                    buf01 = std::clog.rdbuf(file->rdbuf());
                else
                    std::clog.rdbuf(file->rdbuf());
            }
            /* et nous prenons note du fait qu'il faut une écriture */
            log = true;
        }
        else
        {
            /* si on ne désire plus de fichier "log",
             * on détruit proprement le fichier,
             * on redéfini le buffer de clog à son état d'origine,
             * et on prend note qu'il ne faut plus d'écriture
             */
            delete file;
            file = NULL;
            if(buf01)
                std::clog.rdbuf(buf01);
            log = false;
        }
        return *this;
    }
    et l'utilisation pourrait se faire 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
    12
    13
    14
    15
    16
    #include "Sender.hpp"
    int main()
    {
        Sender::instance().setConsole(true)
                          .send("Salut console uniquement")
                          .setConsole(false)
                          .send("Salut non visible")
                          .setLog(true)
                          .send("salut log uniquement")
                          .setConsole(true)
                          .send("Salut console et log")
                          .setLog(true,"log.txt")
                          .send("Salut console et log (fichier)");
     
        return 0;
    }
    [EDIT]Tu l'auras compris, l'appel à setConsole et / ou setLog se fait de manière générale dans les "options de configuration", et l'appel à send se fait partout où, selon la configuration, il te faut un affichage (ou une sortie "log")

    Au final, dans une classe donnée, cela peut prendre la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void MaClass::foo()
    {
        Sender::instance().send("nous somme dans la fonction foo de MaClass")
                          .send(*this);
    }
    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

  10. #10
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Intéressant, merci.
    J'ai ajouté ceci à ta classe Sender
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    	template <class T>
    	Sender & operator<<(const T & t)
    	{
    		if (console)
    			std::cout << t;
    		if (log)
    			std::clog << t;
    		return *this;
    	}
    Et puis je fais un appel comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sender.setConsole(true) << 25 << " abc";
    Mais lorsque je fais ceci, c'est badaboum, le compilateur ne veut pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sender.setConsole(true) << 25 << " abc" << std::endl;
    Par contre ceci est bon
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sender.setConsole(true) << std::setw(4) << 25 << " abc";
    Une idée pourquoi ? Quelle est la contrainte avec std::endl ?

  11. #11
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par camboui Voir le message
    Quelle est la contrainte avec std::endl ?
    C'est une fonction template utilisee dans un contexte ou elle n'est pas deductible (il y a deux templates dont il faut deduire les arguments templates: endl et operator<<).

    Normalement ajouter un membre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Sender& operator<<(std::ostream& (*fn)(std::ostream&));
    devrait regler ce probleme.

    En passant, la technique que j'emploie pour faire cela est de me definir un streambuf (place dans un ostream) qui envoie au choix vers les deux streambufs cibles. C'est plus propre, ca evite de formater deux fois, on peut utiliser tout ce qui prend un ostream. La FAQ de fr.comp.lang.c++ contient un exemple de definition de streambuf.

  12. #12
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    En passant, la technique que j'emploie pour faire cela est de me definir un streambuf (place dans un ostream) qui envoie au choix vers les deux streambufs cibles. C'est plus propre, ca evite de formater deux fois, on peut utiliser tout ce qui prend un ostream. La FAQ de fr.comp.lang.c++ contient un exemple de definition de streambuf.
    Je trouve aussi que c'est beaucoup plus propre. Tu as un lien direct vers l'exemple, ou simplement vers la faq dont tu parles ? (je ne trouve pas)

  13. #13
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par camboui Voir le message
    Je trouve aussi que c'est beaucoup plus propre. Tu as un lien direct vers l'exemple, ou simplement vers la faq dont tu parles ? (je ne trouve pas)
    Malheureusement elle a l'air d'avoir ete viree... Bon, recourons aux grands moyens.

    http://web.archive.org/web/200701280...sreis/C++/FAQ/

  14. #14
    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
    Sans passer par les archives elle est hébergé ici :

    http://www.decima.org/c++/faq-fclc++.txt


    quoique elle est moins complète apparemment.... surement une ancienne version.

  15. #15
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Goten Voir le message
    Sans passer par les archives elle est hébergé ici :

    http://www.decima.org/c++/faq-fclc++.txt
    Je sais. Mais sans la partie qui interesse ici...

  16. #16
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    {o,i}strstream ne sont pas dépréciées, au passage ?

  17. #17
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Je ne sais plus leur status exact. Ils l'ont été, il me semble, mais comme ils remplissent un besoin non remplis par les autres (un gain d'allocation), je ne sais plus s'ils le sont encore.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  18. #18
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Je ne sais plus leur status exact. Ils l'ont été, il me semble, mais comme ils remplissent un besoin non remplis par les autres (un gain d'allocation),
    Ce n'est pas particulièrement le gain d'une allocation, c'est l'utilisation d'une zone mémoire bien spécifiée (en multithread, o
    je ne sais plus s'ils le sont encore.
    Dans le CD de C++0X, c'est toujours dans l'annexe D (Compatibility Features) et donc deprecated where deprecated is defined as: Normative for the current edition of the Standard, but not guaranteed to be part of the Standard in future revisions.

  19. #19
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Allez, hop, résolu, et j'oublie l'existence de strstream au profit de stringstream

  20. #20
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Une petite question. Comment connaître la longueur de ce qui est contenu dans un ostringstream ?
    Pour l'instant je fais long p=ss.tellp(); mais je ne suis sûr que ce soit correct.
    Merci.

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

Discussions similaires

  1. A propos de std::streambuf
    Par bowow dans le forum C++
    Réponses: 10
    Dernier message: 14/05/2015, 15h33
  2. A propos de std::istreambuf_iterator<>
    Par bowow dans le forum C++
    Réponses: 2
    Dernier message: 29/04/2015, 00h15
  3. Réponses: 18
    Dernier message: 19/08/2011, 16h21
  4. question à propos d'un std::vector encapsuler
    Par Date90 dans le forum C++
    Réponses: 2
    Dernier message: 05/04/2009, 15h20
  5. A propos du composant DBGrid
    Par _Rico_ dans le forum C++Builder
    Réponses: 2
    Dernier message: 24/07/2002, 09h18

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