599 Stimmen

Wie löscht man eine stringstream Variable?

Ich habe bereits mehrere Dinge versucht,

std::stringstream m;
m.empty();
m.clear();

beide funktionieren nicht.

943voto

Wilka Punkte 27444

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.

138 Stimmen

Hier ist, was passiert, wenn Sie den "clear()" Teil vergessen. stackoverflow.com/q/2848087/635549

0 Stimmen

Warum gibt die m.str() Methode die Zeichenfolgenwerte zurück, aber leert den Stream nicht?

9 Stimmen

@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.

78voto

Nikos Athanasiou Punkte 26657

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;
}

Demo

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:

  • Der konstruierte String-Stream (392 Bytes)
  • Der zusätzliche für das Payload benötigte Puffer (513 Bytes). Die überflüssige Größe hängt mit der Allokationsstrategie zusammen, die vom Stream gewählt wurde und für Payloads <= 8 Bytes können Blöcke innerhalb des ursprünglichen Objekts verwendet werden.

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.

6 Stimmen

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.

5 Stimmen

Funktionalität fehlt immer noch in GNU g++ v4.8, siehe stackoverflow.com/questions/24429441/…

9 Stimmen

@101010: Wie ist das Tauschen besser als das Verschieben?

48voto

jerron Punkte 397

Dies sollte unabhängig vom Compiler der zuverlässigste Weg sein:

m=std::stringstream();

3 Stimmen

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.

3 Stimmen

Ich hatte dasselbe Problem, für mich mm.clear(); mm.str(""); hat funktioniert. (kein C++11, sonst wäre swap besser).

1 Stimmen

@hochl: Warum wäre swap besser als Move-Zuweisung?

39voto

m.str("");

scheint zu funktionieren.

3 Stimmen

Das würde durch .clear() gelöscht werden, das im OP angegeben ist.

18voto

TimoK Punkte 193

Ich scope es immer:

{
    std::stringstream ss;
    ss << "was";
}

{
    std::stringstream ss;
    ss << "das";
}

{
    std::stringstream ss;
    ss << "heck";
}

1 Stimmen

Ist das besser als das Löschen des stringstream?

CodeJaeger.com

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.

Powered by:

X