Comment réutiliser un ostringstream?

Réponses:

156

J'ai utilisé une séquence de clear et str dans le passé:

// clear, because eof or other bits may be still set. 
s.clear();
s.str("");

Ce qui a fait la chose pour les flux de chaînes d'entrée et de sortie. Vous pouvez également effacer manuellement, puis rechercher la séquence appropriée pour commencer:

s.clear();
s.seekp(0); // for outputs: seek put ptr to start
s.seekg(0); // for inputs: seek get ptr to start

Cela empêchera certaines réallocations effectuées en strécrasant ce qui se trouve actuellement dans le tampon de sortie. Les résultats sont comme ceci:

std::ostringstream s;
s << "hello";
s.seekp(0);
s << "b";
assert(s.str() == "bello");

Si vous souhaitez utiliser la chaîne pour les fonctions c, vous pouvez utiliser std::ends, en mettant un null de fin comme ceci:

std::ostringstream s;
s << "hello";
s.seekp(0);
s << "b" << std::ends;
assert(s.str().size() == 5 && std::strlen(s.str().data()) == 1);

std::endsest une relique de la version obsolète std::strstream, qui était capable d'écrire directement dans un tableau de caractères que vous avez alloué sur la pile. Vous deviez insérer un null de fin manuellement. Cependant, std::endsn'est pas obsolète, je pense parce que c'est toujours utile comme dans les cas ci-dessus.

Johannes Schaub - litb
la source
J'essaye d'utiliser s.str () avec un ostream. La taille le gâche (je peux voir que le premier caractère est nul mais il imprime beaucoup plus). Existe-t-il un bon moyen de fixer la longueur de la chaîne? j'utilise s.str (). c_str (); ATM et ça marche bien
En fait, même ce n'est pas correct. J'ai juste fait à la s.str("");place. auto str = s.str(); auto cstr = str.c_str(); file << cstr; s.clear(); s.seekp(0); s << ends;
le std :: ends ne fonctionne pas pour moi dans le test google boost::any a = 1; std::ostringstream buffer; buffer << a << std::ends; EXPECT_EQ( buffer.str(), "any<(int)1>" ); TestUtilsTest.cpp:27: Failure Expected: buffer.str() Which is: "any<(int)1>\0" To be equal to: "any<(int)1>" et si je réutilise avec des chaînes de longueur différente, il me reste des bits
David van Laatum
L'Alternative est la vraie réponse si vous voulez éviter une réaffectation. Et si vous voulez vraiment "repartir à zéro" sans réallocation, appelez à nouveau seekp (0) après avoir envoyé std :: end. s.seekp(0); s << std::ends; s.seekp(0);
Chip Grandits
5

Il semble que l' ostr.str("")appel fasse l'affaire.

Diego Séville
la source
9
Il convient de souligner que cela ne réutilisera pas le tampon sous-jacent de l'ostringstream - il affecte simplement un nouveau tampon. Ainsi, pendant que vous réutilisez l'objet ostringstream, vous allouez toujours deux tampons. Je ne pense pas qu'ostringstream soit conçu pour être réutilisé comme vous l'entendez.
razlebe
2
Cela n'efface pas non plus l'état, ce que fait .clear (). Je suis d'accord, ce n'est vraiment pas destiné à être utilisé comme ça. Créez-en un nouveau pour être sûr. Ce n'est que si vous profilez que vous saurez si cela fait une différence.
Brian Neal
1
sgreeve, Brian, c'est vrai. Notez, cependant, comment la méthode de litb ci-dessus nécessite l'utilisation de std :: ends. Il réutilise le tampon, mais vous fait coder différemment comme d'habitude avec des chaînes de caractères (normalement vous n'utilisez pas std :: ends).
Diego Sevilla
2

Si vous voulez effacer le tampon d'une manière qui le fera effacer avant sa première utilisation, vous devrez d'abord ajouter quelque chose au tampon avec MSVC.

struct Foo {
    std::ostringstream d_str;
    Foo() { 
        d_str << std::ends;   // Add this
    }
    void StrFunc(const char *);
    template<class T>
    inline void StrIt(const T &value) {
        d_str.clear();
        d_str.seekp(0);  // Or else you'll get an error with this seek
        d_str << value << std::ends;
        StrFunc(d_str.str().c_str());  // And your string will be empty
    }
};
Unkle George
la source
Je ne vois pas le comportement défaillant sur VS2012. En outre, l' appel clearsera provoquer l' failbitêtre ensemble si le flux est vide. Alors que juste appeler seekpdevrait simplement retourner si aucun flux n'existe.
Jonathan Mee
0

Vous ne le faites pas. Utilisez deux flux nommés différemment pour plus de clarté et laissez le compilateur d'optimisation comprendre qu'il peut réutiliser l'ancien.

Sebastian Ganslandt
la source
4
considérez le cas d'utilisation où le code boucle sur les données d'entrée, écrit dans un ostringstream(basé sur les données lues) et doit ensuite écrire la chaîne construite ostringstreamquelque part de temps en temps (par exemple après qu'une certaine séquence de caractères a été lue) et commencer construire une nouvelle chaîne.
Andre Holzner