Cosa fa esattamente lo stringstream?


107

Sto cercando di imparare il C ++ da ieri e sto usando questo documento: http://www.cplusplus.com/files/tutorial.pdf (pagina 32). Ho trovato un codice nel documento e l'ho eseguito. Ho provato a inserire Rs 5.5 per il prezzo e un numero intero per la quantità e l'output era 0. Ho provato a inserire 5.5 e 6 e l'output era corretto.

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

Domanda: cosa fa esattamente il comando mystring? Citando dal documento:

"In questo esempio, acquisiamo indirettamente valori numerici dallo standard input. Invece di estrarre i valori numerici direttamente dallo standard input, otteniamo linee dallo standard input (cin) in un oggetto stringa (mystr), quindi estraiamo il numero intero valori da questa stringa in una variabile di tipo int (quantità). "

La mia impressione è stata che la funzione prendesse la parte integrante di una stringa e la usasse come input.

(Non so esattamente come fare una domanda qui. Sono anche nuovo nella programmazione) Grazie.


18
Questo esempio è un po 'strano, non l'ho mai visto stringstreamusato in questo modo. Di solito carico la riga, la converto e poi la estraggo per parti, tuttavia questo ovviamente ha poco vantaggio qui perché cin è già un flusso di input ... Quindi cin >> price >> quantity;sarebbe di gran lunga più semplice. Questa sarebbe una buona ragione per NON usare i tutorial di cplusplus.com.
Bartek Banachewicz

6
Buffo che quel tutorial sia stato il mio primo contatto con C ++. Col senno di poi, è piuttosto scadente e incompleto. Suggerirei invece un buon libro .
jrok

@BartekBanachewicz Forse avevano solo bisogno di trovare un esempio per mostrare come stringstreamfunziona. È bizzarro probabilmente anche cattivo =) Ma mostra che puoi trattare la stringa come un flusso.
luk32

Se non è un'introduzione a usi più avanzati, stringstreamallora è sicuramente un esempio sbagliato. E anche se lo è, dovrebbe essere scritto in modo diverso.
j_kubik

1
@trojansdestroy Non puoi capire lo stringstream senza capire tutte le primitive su cui si basa, quindi non vedo come la lettura di un tutorial aiuti in questo senso.
Bartek Banachewicz

Risposte:


163

A volte è molto conveniente usare stringstream per convertire tra stringhe e altri tipi numerici. L'uso di stringstreamè simile all'uso di iostream, quindi non è un peso da imparare.

Stringstreams può essere utilizzato sia per leggere stringhe che per scrivere dati in stringhe. Funziona principalmente con un buffer di stringa, ma senza un vero canale di I / O.

Le funzioni membro di base della classe stringstream sono

  • str(), che restituisce il contenuto del suo buffer in tipo stringa.

  • str(string), che imposta il contenuto del buffer sull'argomento stringa.

Ecco un esempio di come utilizzare i flussi di stringhe.

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

Il risultato è dec: 15 hex: f.

istringstream è più o meno lo stesso utilizzo.

Per riassumere, stringstream è un modo conveniente per manipolare le stringhe come un dispositivo I / O indipendente .

Cordiali saluti, le relazioni di ereditarietà tra le classi sono:

classi di flusso di stringhe


19

Per rispondere alla domanda. stringstreamfondamentalmente ti permette di trattare un stringoggetto come un stream, e di usare tutte le streamfunzioni e gli operatori su di esso.

L'ho visto usato principalmente per la bontà di output / input formattato.

Un buon esempio potrebbe essere l' c++implementazione della conversione del numero in un oggetto di flusso.

Possibile esempio:

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

Forse è un po 'complicato ma è piuttosto complesso. Si crea un stringstreamoggetto ss, si modificano i suoi flag, si inserisce un numero con operator<<e lo si estrae tramite str(). Immagino che operator>>potrebbe essere usato.

Anche in questo esempio il stringbuffer è nascosto e non utilizzato esplicitamente. Ma sarebbe un post troppo lungo scrivere su ogni possibile aspetto e caso d'uso.

Nota: probabilmente l'ho rubato da qualcuno su SO e perfezionato, ma non ho notato l'autore originale.


3
Nota: l'uso di retnon è necessario, si potrebbe scrivere return ss.str();.
Matthieu M.

@MatthieuM. Penso che non ero sicuro se RVO sarebbe entrato in azione se fosse stato scritto così, o se l'oggetto restituito da ss.str () sarebbe sopravvissuto al punto di uscita. In questo modo so che sto facendo una copia e RVO funzionerà. Ma molto probabilmente hai ragione.
luk32

In realtà, ci sono 2 forme di RVO: URVO (per senza nome, cioè provvisori) e NRVO (per nome); la maggior parte dei compilatori implementa RVO, ma alcuni lo limitano solo a URVO (a seconda delle opzioni di compilazione). In generale, tuttavia, ci sono molti altri fattori da prendere in considerazione, quindi dovresti semplicemente scrivere il codice più pulito possibile e non preoccuparti troppo se RVO entrerà in funzione.
Matthieu M.

NRVO è comune (come URVO), tuttavia non è un problema a causa dello spostamento dei costruttori.
Rapptz

18

Da C ++ Primer :

Il tipo istringstream legge una stringa , ostringstream scrive una stringa e stringstream legge e scrive la stringa .

Mi imbatto in alcuni casi in cui è conveniente e conciso usare stringstream .

caso 1

Proviene da una delle soluzioni per questo problema di leetcode . Dimostra un caso molto adatto in cui l'uso di stringstream è efficiente e conciso.

Supponiamo ache bsiano numeri complessi espressi in formato stringa, di voler ottenere il risultato della moltiplicazione di ae banche in formato stringa. Il codice è il seguente:

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() 

caso 2

È anche da un problema di leetcode che richiede di semplificare la stringa del percorso data, una delle soluzioni che utilizzano stringstream è la più elegante che ho visto:

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

Senza l'uso di stringstream, sarebbe difficile scrivere un codice così conciso.


2

Hai inserito caratteri alfanumerici e int, delimitati da spazi mystr.

Hai quindi provato a convertire il primo token (delimitato da spazi) in un file int.

Il primo token è stato RS che non è riuscito a convertire int, lasciando uno zero per il mio prezzo, e sappiamo tutti cosa produce zero volte qualcosa.

Quando hai inserito valori int solo la seconda volta, tutto ha funzionato come previsto.

È stata la falsa RS che ha causato il fallimento del codice.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.