Wie kann man einen Ostringstream wiederverwenden?

Antworten:

156

Ich habe in der Vergangenheit eine Folge von clear und str verwendet:

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

Was sowohl für Input- als auch für Output-Stringstreams funktioniert hat. Alternativ können Sie manuell löschen und dann zu Beginn die entsprechende Reihenfolge suchen:

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

Dies verhindert einige Neuzuweisungen, indem strstattdessen alles überschrieben wird, was sich derzeit im Ausgabepuffer befindet. Die Ergebnisse sind wie folgt:

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

Wenn Sie die Zeichenfolge für c-Funktionen verwenden möchten, können Sie std::endseine abschließende Null wie folgt setzen:

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

std::endsist ein Relikt des Veralteten std::strstream, das direkt in ein Char-Array schreiben konnte, das Sie auf dem Stapel zugewiesen haben. Sie mussten manuell eine abschließende Null einfügen. Allerdings std::endsist nicht veraltet, denke ich, weil es immer noch nützlich ist, wie in den oben genannten Fällen.

Johannes Schaub - litb
quelle
Ich versuche s.str () mit einem ostream zu verwenden. Die Größe bringt es durcheinander (ich kann sehen, dass das erste Zeichen null ist, aber es druckt viel mehr). Gibt es eine gute Möglichkeit, die Str-Länge zu fixieren? ich benutze s.str (). c_str (); Geldautomat und es funktioniert gut
Eigentlich ist auch das nicht richtig. Ich habe es s.str("");stattdessen einfach getan . auto str = s.str(); auto cstr = str.c_str(); file << cstr; s.clear(); s.seekp(0); s << ends;
Das std :: Enden funktioniert nicht für mich in Google Test 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>" und wenn ich mit Strings unterschiedlicher Länge wiederverwenden, bleiben mir Bits übrig
David van Laatum
Die Alternative ist die richtige Antwort, wenn Sie eine Neuzuweisung vermeiden möchten. Und wenn Sie ohne Neuzuweisung wirklich "neu anfangen" möchten, rufen Sie einfach seekp (0) erneut auf, nachdem Sie std :: end gesendet haben. s.seekp(0); s << std::ends; s.seekp(0);
Chip Grandits
5

Scheint, dass der ostr.str("")Anruf den Trick macht.

Diego Sevilla
quelle
9
Es sei darauf hingewiesen, dass dadurch der zugrunde liegende Puffer aus dem ostringstream nicht wiederverwendet wird, sondern lediglich ein neuer Puffer zugewiesen wird. Während Sie das ostringstream-Objekt wiederverwenden, weisen Sie dennoch zwei Puffer zu. Ich glaube nicht, dass ostringstream für die Wiederverwendung in der von Ihnen beabsichtigten Weise ausgelegt ist.
Razlebe
2
Es löscht auch nicht den Zustand, was .clear () tut. Ich stimme zu, es ist wirklich nicht dazu gedacht, so verwendet zu werden. Erstellen Sie einfach eine neue, um sicherzugehen. Nur wenn Sie ein Profil haben, werden Sie herausfinden, ob es einen Unterschied macht.
Brian Neal
1
sgreeve, Brian, das stimmt. Beachten Sie jedoch, wie die obige Methode von litb die Verwendung von std :: Enden erfordert. Der Puffer wird wiederverwendet, aber Sie codieren anders als bei Stringstreams üblich (normalerweise verwenden Sie nicht std :: Enden).
Diego Sevilla
2

Wenn Sie den Puffer so löschen möchten, dass er vor seiner ersten Verwendung gelöscht wird, müssen Sie dem Puffer zuerst mit MSVC etwas hinzufügen.

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
quelle
Ich sehe das fehlerhafte Verhalten auf VS2012 nicht. Darüber hinaus fordern clearwird dazu führen , die failbitgesetzt werden , wenn der Strom ist leer. Während nur anrufen seekpsollte einfach zurückkehren, wenn kein Stream existiert.
Jonathan Mee
0

Das tust du nicht. Verwenden Sie aus Gründen der Übersichtlichkeit zwei Streams mit unterschiedlichen Namen und lassen Sie den optimierenden Compiler herausfinden, dass er den alten wiederverwenden kann.

Sebastian Ganslandt
quelle
4
Betrachten Sie den Anwendungsfall, in dem der Code Eingabedaten durchläuft, in eine ostringstream(basierend auf den gelesenen Daten) schreibt und dann ostringstreamvon Zeit zu Zeit (z. B. nachdem eine bestimmte Zeichenfolge gelesen wurde) die eingebaute Zeichenfolge irgendwo schreibt und startet Erstellen einer neuen Zeichenfolge.
Andre Holzner