Ich habe bereits mehrere Dinge versucht,
std::stringstream m;
m.empty();
m.clear();
beide funktionieren nicht.
Ich habe bereits mehrere Dinge versucht,
std::stringstream m;
m.empty();
m.clear();
beide funktionieren nicht.
Für alle Standardbibliothekstypen ist die Member-Funktion empty()
eine Abfrage, keine Anweisung, d.h. sie bedeutet "bist du leer?" nicht "bitte wirf deinen Inhalt weg".
Die Member-Funktion clear()
wird von ios
geerbt und dient dazu, den Fehlerzustand des Streams zu löschen, z.B. wenn der Fehlerzustand eines Dateistreams auf eofbit
(Ende der Datei) gesetzt ist, dann setzt ein Aufruf von clear()
den Fehlerzustand zurück auf goodbit
(kein Fehler).
Zum Löschen des Inhalts eines stringstreams
benutzen Sie:
m.str("");
ist korrekt, obwohl die Verwendung von:
m.str(std::string());
technisch effizienter ist, weil sie es vermeiden, den Konstruktor von std::string
aufzurufen, der const char*
akzeptiert. Aber jeder Compiler sollte heutzutage in beiden Fällen den gleichen Code generieren können - also würde ich einfach das verwenden, was lesbarer ist.
Hier ist, was passiert, wenn Sie den "clear()" Teil vergessen. stackoverflow.com/q/2848087/635549
Warum gibt die m.str() Methode die Zeichenfolgenwerte zurück, aber leert den Stream nicht?
@KshitijBanerjee Ich denke, in C++ sind m.str() und m.str("") zwei verschiedene Funktionen. m.str() ruft eine Funktion auf, die keinen Parameter erwartet, während m.str("") die Funktion aufruft, die einen const char* Parameter akzeptiert. m.str() könnte als get-Funktion implementiert worden sein, die den String zurückgibt, während m.str("") als set-Funktion implementiert worden sein könnte.
Sie können den Fehlerzustand löschen und den stringstream leeren alles in einer Zeile bereinigen
std::stringstream().swap(m); // m mit einem standardmäßig konstruierten stringstream vertauschen
Dadurch wird m effektiv auf einen standardmäßig konstruierten Zustand zurückgesetzt, was bedeutet, dass die Puffer, die vom stringstream allokiert wurden, tatsächlich gelöscht und der Fehlerzustand zurückgesetzt werden. Hier ist ein experimenteller Beweis:
int main ()
{
std::string payload(16, 'x');
std::stringstream *ss = new std::stringstream; // Erzeuge ein Memory-Leak
(*ss) << payload; // Mehr Speicherverlust
// Wählen Sie nun eine Möglichkeit, einen String-Stream "zu löschen"
//std::stringstream().swap(*ss); // Methode 1
//ss->str(std::string()); // Methode 2
std::cout << "end" << std::endl;
}
Wenn die Demo mit dem Adress-Sanitizer kompiliert wird, wird der Speicherverbrauch angezeigt:
=================================================================
==10415==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 392 byte(s) in 1 object(s) allocated from:
#0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
#1 0x514e80 in main (/tmp/1637178326.0089633/a.out+0x514e80)
#2 0x7f3079ffb82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291
Indirect leak of 513 byte(s) in 1 object(s) allocated from:
#0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
#1 0x7f307b03a25c in std::__cxx11::basic_string, std::allocator >::reserve(unsigned long) (/usr/local/lib64/libstdc++.so.6+0x13725c)
#2 0x603000000010 ()
SUMMARY: AddressSanitizer: 905 byte(s) leaked in 2 allocation(s).
Ziemlich steil, wenn Sie mich fragen. Um nur 16 Bytes Payload zu speichern, haben wir 905 Bytes ausgegeben ... Stringstreams sind kein Spielzeug. Der Speicher wird in zwei Teilen allokiert:
Wenn Sie Methode 1 aktivieren (die in dieser Antwort gezeigte), werden die zusätzlichen 513 (Payload) Bytes zurückgewonnen, da der Stream tatsächlich gelöscht wird.
Wenn Sie Methode 2 aktivieren, wie in den Kommentaren oder anderen Antworten vorgeschlagen, sehen Sie, dass zum Zeitpunkt des Beendens alle 905 Bytes verwendet werden.
In Bezug auf die Programmsemantik kann es sein, dass es dem Benutzer nur wichtig ist, dass der Stream "erscheint" und sich "verhält", als ob er leer wäre, ähnlich wie bei einem vector::clear
, wo die Kapazität unverändert bleibt, aber der Vektor für den Benutzer leer ist (natürlich würde ein Vektor hier nur 16 Bytes ausgeben). Angesichts der Speicherzuweisung, die der String-Stream erfordert, kann ich mir vorstellen, dass dieser Ansatz oft schneller ist. Das Hauptziel dieser Antwort besteht darin, den String-Stream tatsächlich zu löschen, da der damit verbundene Speicherverbrauch nicht zu unterschätzen ist. Je nach Anwendungsfall (Anzahl der Streams, die gehalten werden, Daten, die sie enthalten, Häufigkeit des Löschens) können Sie die beste Methode wählen.
Schließlich sei darauf hingewiesen, dass es selten sinnvoll ist, den Stream zu löschen, ohne den Fehlerzustand und alle vererbten Zustände zu löschen. Mit der Einzeiler in dieser Antwort wird beides erledigt.
Das ist der effizienteste und eleganteste Weg, es im Vergleich zu allen anderen Antworten hier zu tun. Allerdings ist std::stringstream::swap eine c++11 Funktion und diese Lösung funktioniert nicht für frühere c++11 Compiler.
Funktionalität fehlt immer noch in GNU g++ v4.8, siehe stackoverflow.com/questions/24429441/…
Das ist meiner Meinung nach besser, weil m.str(""); dazu geführt hat, dass mein stringstream mit diesem leeren Wert stecken blieb, egal was ich versucht habe. Aber mit diesem Befehl habe ich dieses Problem nicht.
Ich hatte dasselbe Problem, für mich mm.clear(); mm.str("");
hat funktioniert. (kein C++11, sonst wäre swap besser).
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.