Que fait exactement stringstream?

107

J'essaye d'apprendre le C ++ depuis hier et j'utilise ce document: http://www.cplusplus.com/files/tutorial.pdf (page 32). J'ai trouvé un code dans le document et je l'ai exécuté. J'ai essayé d'entrer Rs 5,5 pour le prix et un entier pour la quantité et la sortie était de 0. J'ai essayé d'entrer 5,5 et 6 et la sortie était correcte.

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

Question: Que fait exactement la commande mystring? Citant le document:

"Dans cet exemple, nous acquérons indirectement des valeurs numériques à partir de l'entrée standard. Au lieu d'extraire des valeurs numériques directement de l'entrée standard, nous obtenons des lignes de l'entrée standard (cin) dans un objet chaîne (mystr), puis nous extrayons l'entier valeurs de cette chaîne dans une variable de type int (quantité). "

Mon impression était que la fonction prendra la partie intégrante d'une chaîne et l'utilisera comme entrée.

(Je ne sais pas exactement comment poser une question ici. Je suis également nouveau dans la programmation) Merci.

jacknad
la source
18
Cet exemple est un peu bizarre, je n'ai jamais vu stringstreamutilisé de cette façon. Habituellement, je charge la ligne, la convertit puis l'extrait par parties, mais cela n'a évidemment que peu d'avantages ici car il cin s'agit déjà d'un flux d'entrée ... Ce cin >> price >> quantity;serait donc de loin plus simple. Ce serait une bonne raison de NE PAS utiliser les didacticiels cplusplus.com.
Bartek Banachewicz
6
C'est drôle que ce tutoriel ait été ma première exposition au C ++. Avec le recul, c'est assez pauvre et incomplet. Je suggérerais plutôt un bon livre .
jrok
@BartekBanachewicz Peut-être qu'ils avaient juste besoin de trouver un exemple pour montrer comment ça stringstreammarche. C'est un exemple bizarre probablement même mauvais =) Mais cela montre que vous pouvez traiter la chaîne comme un flux.
luk32
Si ce n'est pas une introduction à des utilisations plus avancées, stringstreamc'est certainement un mauvais exemple. Et même si c'est le cas, il devrait être écrit différemment.
j_kubik
1
@trojansdestroy Vous ne pouvez pas comprendre stringstream sans comprendre toutes les primitives sur lesquelles il est basé, donc je ne vois pas comment la lecture d'un tutoriel aide à cet égard.
Bartek Banachewicz

Réponses:

163

Parfois, il est très pratique d'utiliser stringstream pour convertir entre des chaînes et d'autres types numériques. L'utilisation de stringstreamest similaire à l'utilisation de iostream, donc ce n'est pas un fardeau à apprendre.

Les chaînes de caractères peuvent être utilisées à la fois pour lire des chaînes et pour écrire des données dans des chaînes. Il fonctionne principalement avec un tampon de chaîne, mais sans véritable canal d'E / S.

Les fonctions membres de base de la classe stringstream sont

  • str(), qui renvoie le contenu de son tampon sous forme de chaîne.

  • str(string), qui définit le contenu du tampon sur l'argument chaîne.

Voici un exemple d'utilisation des flux de chaînes.

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

Le résultat est dec: 15 hex: f.

istringstream est plus ou moins du même usage.

Pour résumer, stringstream est un moyen pratique de manipuler des chaînes comme un périphérique d'E / S indépendant .

Pour info, les relations d'héritage entre les classes sont:

classes de flux de chaînes

richard.g
la source
19

Pour répondre à la question. stringstreamvous permet essentiellement de traiter un stringobjet comme un stream, et d'utiliser toutes les streamfonctions et opérateurs sur celui-ci.

Je l'ai vu utilisé principalement pour la qualité de sortie / entrée formatée.

Un bon exemple serait la c++mise en œuvre de la conversion d'un nombre en objet de flux.

Exemple possible:

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

C'est peut-être un peu compliqué mais c'est assez complexe. Vous créez un stringstreamobjet ss, modifiez ses drapeaux, mettez un numéro dedans avec operator<<, et extrayez-le via str(). Je suppose que cela operator>>pourrait être utilisé.

Dans cet exemple également, le stringtampon est masqué et n'est pas utilisé explicitement. Mais ce serait trop long pour écrire sur tous les aspects et cas d'utilisation possibles.

Remarque: je l'ai probablement volé à quelqu'un sur SO et affiné, mais je n'ai pas l'auteur original noté.

luk32
la source
3
Remarque: l'utilisation de retn'est pas nécessaire, on pourrait écrire return ss.str();.
Matthieu M.
@MatthieuM. Je pense que je n'étais pas sûr que RVO entrerait en jeu s'il était écrit comme ça, ou si l'objet retourné par ss.str () survivrait au point de sortie. De cette façon, je sais que je fais une copie, et RVO fonctionnera. Mais vous avez probablement raison.
luk32
En fait, il existe 2 formes de RVO: URVO (pour sans nom, c'est-à-dire temporaire) et NRVO (pour nommé); la plupart des compilateurs implémentent RVO, mais certains le limitent à URVO uniquement (en fonction des options de construction). En général, cependant, il y a beaucoup d'autres facteurs à prendre en compte, vous devriez donc simplement écrire le code le plus propre possible et ne pas trop vous soucier de savoir si RVO entrera en vigueur.
Matthieu M.
NRVO est courant (tout comme URVO), mais ce n'est pas un problème en raison du déplacement des constructeurs.
Rapptz
18

À partir de l' amorce C ++ :

Le type istringstream lit une chaîne , ostringstream écrit une chaîne et stringstream lit et écrit la chaîne .

Je rencontre des cas où il est à la fois pratique et concis d'utiliser stringstream .

cas 1

C'est l' une des solutions à ce problème de leetcode . Cela démontre un cas très approprié où l'utilisation de stringstream est efficace et concise.

Supposons que aet bsoient des nombres complexes exprimés au format chaîne, nous voulons obtenir le résultat de la multiplication de aet bégalement au format chaîne. Le code est comme suit:

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

cas 2

C'est aussi à partir d'un problème de leetcode qui vous oblige à simplifier la chaîne de chemin donnée, l' une des solutions utilisant stringstream est la plus élégante que j'ai vue:

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

Sans l'utilisation de stringstream, il serait difficile d'écrire un code aussi concis.

jdhao
la source
2

Vous avez entré un alphanumérique et un entier, délimités par un vide mystr.

Vous avez ensuite essayé de convertir le premier jeton (délimité par des blancs) en un fichier int.

Le premier jeton était RS qui n'a pas réussi à se convertir int, laissant un zéro pour mon prix, et nous savons tous ce que rapporte zéro fois tout.

Lorsque vous n'avez entré des valeurs int que la deuxième fois, tout fonctionnait comme prévu.

C'est le faux RS qui a causé l'échec de votre code.

ilocos joe
la source