Pytanie Co dokładnie robi stringstream?


Próbuję uczyć się C ++ od wczoraj i używam tego dokumentu:http://www.cplusplus.com/files/tutorial.pdf (strona 32). Znalazłem kod w dokumencie i uruchomiłem go. Próbowałem wprowadzić Rs 5.5 dla ceny i liczbę całkowitą dla ilości, a wynik wynosił 0. Próbowałem wprowadzić 5.5 i 6, a wynik był poprawny.

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

Pytanie: Co dokładnie robi polecenie mystring? Cytowanie z dokumentu:

"W tym przykładzie otrzymujemy wartości liczbowe ze standardowego wejścia   pośrednio. Zamiast wyodrębniać wartości liczbowe bezpośrednio z   standardowe wejście, otrzymujemy linie ze standardowego wejścia (cin) do a   string object (mystr), a następnie wyodrębniamy wartości całkowite z   ten ciąg w zmiennej typu int (ilość). "

Mam wrażenie, że funkcja przyjmie integralną część ciągu i użyje go jako danych wejściowych.

(Nie wiem dokładnie, jak zadać pytanie tutaj, jestem też nowy w programowaniu) Dziękuję Ci.


76
2017-12-15 12:31


pochodzenie


Ten przykład jest trochę dziwny, nigdy go nie widziałem stringstream używany w ten sposób. Zwykle ładuję linię, konwertuję ją, a następnie wyodrębniam przez części, ale to oczywiście ma niewielką przewagę, ponieważ cin  jest strumień wejściowy już ... Tak cin >> price >> quantity; byłoby znacznie prostsze. To byłby dobry powód NIE korzystać z samouczków cplusplus.com. - Bartek Banachewicz
Zabawne, że ten samouczek był moją pierwszą ekspozycją na C ++. Z perspektywy czasu jest dość uboga i niekompletna. Proponuję dobra książka zamiast. - jrok
@BartekBanachewicz Może po prostu musieli wymyślić przykład, aby pokazać, jak stringstream Prace. To jest dziwaczne, prawdopodobnie nawet złe =) Ale pokazuje, że możesz traktować ciąg jako strumień. - luk32
Jeśli nie jest wprowadzeniem do bardziej zaawansowanych zastosowań stringstream to zdecydowanie jest zły przykład. A nawet jeśli tak jest, to powinno być napisane inaczej. - j_kubik
@trojansdestroy Nie możesz zrozumieć stringów bez zrozumienia wszystkich prymitywów, na których bazuje, więc nie widzę, jak czytanie tutoriala pomaga w tym zakresie. - Bartek Banachewicz


Odpowiedzi:


Czasami bardzo wygodne jest użycie strumienia string do konwersji między łańcuchami i innymi typami liczbowymi. Wykorzystanie stringstream jest podobny do użycia iostream, więc nie jest ciężarem do nauki.

Łańcuchy strumieniowe mogą być używane zarówno do odczytywania ciągów, jak i do zapisywania danych w łańcuchach. Działa głównie z buforem ciągowym, ale bez rzeczywistego kanału we / wy.

Podstawowymi funkcjami składowymi klasy stringstream są

  • str(), który zwraca zawartość swojego bufora w typie łańcucha.

  • str(string), który ustawia zawartość bufora na argument łańcuchowy.

Oto przykład użycia strumieni ciągów.

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

Wynik to dec: 15 hex: f.

istringstream ma mniej więcej takie samo zastosowanie.

Podsumowując, stringstream jest wygodnym sposobem manipuluj ciągami jak niezależne urządzenie I / O.

Dla FYI relacje dziedziczenia między klasami są następujące:

string stream classes


120
2017-12-15 13:28





Aby odpowiedzieć na pytanie. stringstream w zasadzie pozwala leczyć string obiekt jak streami użyj wszystkich stream funkcje i operatorzy na nim.

Widziałem, że był używany głównie do sformatowanej dobroci wyjścia / wejścia.

Dobry przykład c++ implementacja konwersji liczby do strumienia obiektu.

Możliwy przykład:

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

Może to trochę skomplikowane, ale jest dość skomplikowane. Tworzysz stringstream obiekt ss, zmodyfikuj jego flagi, umieść w nim numer operator<<i wyodrębnij je przez str(). zgaduję, że operator>> może być użyty.

Również w tym przykładzie string bufor jest ukryty i nie jest używany jawnie. Ale byłoby zbyt długo na napisanie o każdym możliwym aspekcie i przypadku użycia.

Uwaga: Prawdopodobnie ukradłem go komuś z SO i dopracowałem, ale nie odnotowałem oryginalnego autora.


15
2017-12-15 12:47



Uwaga: użycie ret jest niepotrzebne, można pisać return ss.str();. - Matthieu M.
@MatthieuM. Myślę, że nie byłam pewna, czy RVO miałoby się uruchomić, gdyby zostało napisane w ten sposób, czy też obiekt zwrócony przez ss.str () przeżyłby punkt wyjścia. W ten sposób wiem, że robię kopię, a RVO będzie działać. Ale najprawdopodobniej masz rację. - luk32
W rzeczywistości istnieją 2 formy RVO: URVO (dla bezimiennego, czyli tymczasowego) i NRVO (dla nazwanego); większość kompilatorów implementuje RVO, ale niektóre ograniczają go tylko do URVO (w zależności od opcji kompilacji). Ogólnie rzecz biorąc, istnieje wiele innych czynników, które należy wziąć pod uwagę, więc powinieneś po prostu napisać najczystszy możliwy kod i nie martwić się zbytnio o to, czy RVO się pojawi. - Matthieu M.
NRVO jest powszechne (podobnie jak URVO), ale nie jest problemem z powodu konstruktorów ruchu. - Rapptz


Od C ++ Primer:

The istringstream typ czyta a strunowy, ostringstream pisze a strunowy, i stringstream czyta i pisze strunowy.

Natrafiam na niektóre przypadki, w których jest to wygodne i zwięzłe w użyciu stringstream.

przypadek 1

To jest z jedno z rozwiązań dla ten problem z leetcode. Pokazuje bardzo odpowiedni przypadek, w którym użycie stringstream jest wydajny i zwięzły.

Przypuszczać a i b są liczbami zespolonymi wyrażonymi w postaci ciągu, chcemy uzyskać wynik mnożenia a i b również w formacie smyczkowym. Kod jest następujący:

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

sprawa 2

Jest również z Problem z leetcode to wymaga uproszczenia podanego ciągu znaków, jedno z rozwiązań wykorzystujących stringstream jest najbardziej elegancki, jaki widziałem:

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

Bez użycia stringów trudno byłoby napisać tak zwięzły kod.


12
2018-06-27 14:22





Wprowadziłeś alfanumeryczne i int, puste pole rozdzielone mystr.

Następnie próbowałeś przekonwertować pierwszy token (pusty separowany) na int.

Pierwszy token, którego nie udało się przekonwertować na int, pozostawiając zero dla myprice, i wszyscy wiemy, co zero razy cokolwiek daje.

Gdy wprowadziłeś tylko wartości int po raz drugi, wszystko działało zgodnie z oczekiwaniami.

To fałszywy RS spowodował błąd twojego kodu.


2
2017-08-11 02:09