Was genau macht stringstream?

107

Ich versuche seit gestern C ++ zu lernen und verwende dieses Dokument: http://www.cplusplus.com/files/tutorial.pdf (Seite 32). Ich habe einen Code im Dokument gefunden und ihn ausgeführt. Ich habe versucht, Rs 5,5 für den Preis und eine Ganzzahl für die Menge einzugeben, und die Ausgabe war 0. Ich habe versucht, 5,5 und 6 einzugeben, und die Ausgabe war korrekt.

// stringstreams
#include <iostream> 
#include <string> 
#include <sstream> 

using namespace std; 

int main () 
{ 
  string mystr; 
  float price = 0; 
  int quantity = 0; 

  cout << "Enter price: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> price; 
  cout << "Enter quantity: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> quantity; 
  cout << "Total price: " << price*quantity << endl; 
  return 0; 
}

Frage: Was genau macht der Befehl mystring? Zitat aus dem Dokument:

"In diesem Beispiel erfassen wir numerische Werte indirekt aus der Standardeingabe. Anstatt numerische Werte direkt aus der Standardeingabe zu extrahieren, erhalten wir Zeilen aus der Standardeingabe (cin) in ein Zeichenfolgenobjekt (mystr) und extrahieren dann die Ganzzahl Werte aus dieser Zeichenfolge in eine Variable vom Typ int (Menge). "

Mein Eindruck war, dass die Funktion den integralen Bestandteil eines Strings als Eingabe verwendet.

(Ich weiß nicht genau, wie ich hier eine Frage stellen soll. Ich bin auch neu in der Programmierung.) Danke.

Jacknad
quelle
18
Dieses Beispiel ist irgendwie komisch, ich habe es noch nie so gesehen stringstream. Normalerweise lade ich die Zeile, konvertiere sie und extrahiere sie dann nach Teilen, aber das hat hier offensichtlich wenig Vorteil, da cin es sich bereits um einen Eingabestream handelt ... Das cin >> price >> quantity;wäre also weitaus einfacher. Das wäre ein guter Grund , cplusplus.com-Tutorials NICHT zu verwenden.
Bartek Banachewicz
6
Komisch, dass dieses Tutorial meine erste Begegnung mit C ++ war. Im Nachhinein ist es ziemlich arm und unvollständig. Ich würde stattdessen ein gutes Buch vorschlagen .
Jrok
@BartekBanachewicz Vielleicht braucht nur sie mit Beispiel kommen zu zeigen , wie stringstreamfunktioniert. Es ist eine bizarre, wahrscheinlich sogar eine schlechte =) Aber es zeigt, dass Sie String als Stream behandeln können.
luk32
Wenn es keine Einführung in fortgeschrittenere Anwendungen von ist, stringstreamdann ist es definitiv ein falsches Beispiel. Und selbst wenn es so ist, sollte es anders geschrieben werden.
j_kubik
1
@trojansdestroy Sie können stringstream nicht verstehen, ohne alle Grundelemente zu verstehen, auf denen es basiert. Daher sehe ich nicht, wie das Lesen eines Tutorials in dieser Hinsicht hilft.
Bartek Banachewicz

Antworten:

163

Manchmal ist es sehr praktisch, Stringstream zu verwenden, um zwischen Strings und anderen numerischen Typen zu konvertieren. Die Verwendung von stringstreamähnelt der Verwendung von iostream, daher ist das Lernen keine Belastung.

Stringstreams können sowohl zum Lesen von Strings als auch zum Schreiben von Daten in Strings verwendet werden. Es funktioniert hauptsächlich mit einem String-Puffer, jedoch ohne echten E / A-Kanal.

Die grundlegenden Elementfunktionen der Stringstream-Klasse sind

  • str(), der den Inhalt seines Puffers im Zeichenfolgentyp zurückgibt.

  • str(string), die den Inhalt des Puffers auf das String-Argument setzen.

Hier ist ein Beispiel für die Verwendung von String-Streams.

ostringstream os;
os << "dec: " << 15 << " hex: " << std::hex << 15 << endl;
cout << os.str() << endl;

Das Ergebnis ist dec: 15 hex: f.

istringstream ist von mehr oder weniger gleichem Nutzen.

Zusammenfassend ist Stringstream eine bequeme Möglichkeit, Strings wie ein unabhängiges E / A-Gerät zu bearbeiten .

Zu Ihrer Information, die Vererbungsbeziehungen zwischen den Klassen sind:

String-Stream-Klassen

richard.g
quelle
19

Um die Frage zu beantworten. stringstreamGrundsätzlich können Sie ein stringObjekt wie ein Objekt behandeln streamund alle streamFunktionen und Operatoren darauf verwenden.

Ich habe gesehen, dass es hauptsächlich für die formatierte Ausgabe- / Eingabegüte verwendet wird.

Ein gutes Beispiel wäre die c++Implementierung der Konvertierung von Zahlen in Stream-Objekte.

Mögliches Beispiel:

template <class T>
string num2str(const T& num, unsigned int prec = 12) {
    string ret;
    stringstream ss;
    ios_base::fmtflags ff = ss.flags();
    ff |= ios_base::floatfield;
    ff |= ios_base::fixed;
    ss.flags(ff);
    ss.precision(prec);
    ss << num;
    ret = ss.str();
    return ret;
};

Vielleicht ist es ein bisschen kompliziert, aber es ist ziemlich komplex. Sie erstellen ein stringstreamObjekt ss, ändern seine Flags, geben eine Zahl ein operator<<und extrahieren es über str(). Ich denke, das operator>>könnte genutzt werden.

Auch in diesem Beispiel ist der stringPuffer ausgeblendet und wird nicht explizit verwendet. Aber es wäre zu lang, um über jeden möglichen Aspekt und Anwendungsfall zu schreiben.

Hinweis: Ich habe es wahrscheinlich jemandem auf SO gestohlen und verfeinert, aber ich habe keinen Originalautor notiert.

luk32
quelle
3
Hinweis: Die Verwendung von retist unnötig, man könnte schreiben return ss.str();.
Matthieu M.
@MatthieuM. Ich glaube, ich war mir nicht sicher, ob RVO einschalten würde, wenn es so geschrieben wäre, oder ob das von ss.str () zurückgegebene Objekt den Exit-Punkt überleben würde. Auf diese Weise weiß ich, dass ich eine Kopie mache und RVO funktioniert. Aber Sie haben höchstwahrscheinlich recht.
luk32
Tatsächlich gibt es zwei Formen von RVO: URVO (für unbenannte, dh temporäre) und NRVO (für benannte); Die meisten Compiler implementieren RVO, einige beschränken es jedoch nur auf URVO (abhängig von den Erstellungsoptionen). Im Allgemeinen müssen jedoch noch viele andere Faktoren berücksichtigt werden. Sie sollten daher nur den saubersten Code schreiben, der möglich ist, und sich nicht zu viele Gedanken darüber machen, ob RVO aktiv wird.
Matthieu M.
NRVO ist üblich (wie auch URVO), ist jedoch aufgrund von Verschiebungskonstruktoren kein Problem.
Rapptz
18

Von C ++ Primer :

Der Typ istringstream liest eine Zeichenfolge , ostringstream schreibt eine Zeichenfolge und stringstream liest und schreibt die Zeichenfolge .

Ich stoße auf einige Fälle, in denen die Verwendung von Stringstream sowohl bequem als auch prägnant ist .

Fall 1

Es ist eine der Lösungen für dieses Leetcode-Problem . Es zeigt einen sehr geeigneten Fall, in dem die Verwendung von Stringstream effizient und präzise ist.

Angenommen aund bkomplexe Zahlen im String - Format ausgedrückt, wollen wir das Ergebnis der Multiplikation von erhalten aund bauch im String - Format. Der Code lautet wie folgt:

string a = "1+2i", b = "1+3i";
istringstream sa(a), sb(b);
ostringstream out;

int ra, ia, rb, ib;
char buff;
// only read integer values to get the real and imaginary part of 
// of the original complex number
sa >> ra >> buff >> ia >> buff;
sb >> rb >> buff >> ib >> buff;

out << ra*rb-ia*ib << '+' << ra*ib+ia*rb << 'i';

// final result in string format
string result = out.str() 

Fall 2

Aufgrund eines Leetcode-Problems , bei dem Sie die angegebene Pfadzeichenfolge vereinfachen müssen, ist eine der Lösungen, die stringstream verwenden, die eleganteste, die ich je gesehen habe:

string simplifyPath(string path) {
    string res, tmp;
    vector<string> stk;
    stringstream ss(path);
    while(getline(ss,tmp,'/')) {
        if (tmp == "" or tmp == ".") continue;
        if (tmp == ".." and !stk.empty()) stk.pop_back();
        else if (tmp != "..") stk.push_back(tmp);
    }
    for(auto str : stk) res += "/"+str;
    return res.empty() ? "/" : res; 
 }

Ohne die Verwendung von Stringstream wäre es schwierig, solch prägnanten Code zu schreiben.

jdhao
quelle
2

Sie haben eine alphanumerische und eine int-Leerzeichen eingegeben mystr.

Sie haben dann versucht, das erste Token (durch Leerzeichen getrennt) in ein Token umzuwandeln int.

Das erste Token war RS, das nicht konvertiert werden intkonnte und eine Null für myprice hinterließ, und wir alle wissen, was null mal irgendetwas ergibt.

Wenn Sie erst beim zweiten Mal int-Werte eingegeben haben, hat alles wie erwartet funktioniert.

Es war die falsche RS, die dazu führte, dass Ihr Code fehlschlug.

ilocos joe
quelle