O que exatamente stringstream faz?


107

Estou tentando aprender C ++ desde ontem e estou usando este documento: http://www.cplusplus.com/files/tutorial.pdf (página 32). Encontrei um código no documento e o executei. Tentei inserir Rs 5,5 para preço e um inteiro para quantidade e a saída foi 0. Tentei inserir 5,5 e 6 e a saída estava correta.

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

Pergunta: O que exatamente o comando mystring faz? Citação do documento:

"Neste exemplo, adquirimos valores numéricos da entrada padrão indiretamente. Em vez de extrair valores numéricos diretamente da entrada padrão, obtemos linhas da entrada padrão (cin) em um objeto de string (mystr) e, em seguida, extraímos o inteiro valores desta string em uma variável do tipo int (quantidade). "

Minha impressão é que a função pegará a parte integrante de uma string e a usará como entrada.

(Não sei exatamente como fazer uma pergunta aqui. Também sou novo em programação) Obrigado.


18
Esse exemplo é meio estranho, nunca vi ser stringstreamusado assim. Eu geralmente carrego a linha, converto e extraio por partes, no entanto, isso obviamente tem pouca vantagem aqui porque já cin é um fluxo de entrada ... Então cin >> price >> quantity;seria muito mais simples. Essa seria uma boa razão para NÃO usar os tutoriais do cplusplus.com.
Bartek Banachewicz

6
Engraçado que aquele tutorial foi minha primeira exposição ao C ++. Em retrospectiva, é muito pobre e incompleto. Eu sugeriria um bom livro em vez disso.
jrok de

@BartekBanachewicz Talvez eles só precisassem dar um exemplo para mostrar como stringstreamfunciona. É bizarro, provavelmente até ruim =) Mas mostra que você pode tratar cordas como um riacho.
luk32

Se não for uma introdução a usos mais avançados do stringstream, é definitivamente um exemplo errado. E mesmo que seja, deve ser escrito de forma diferente.
j_kubik

1
@trojansdestroy Você não pode entender stringstream sem entender todos os primitivos em que ele se baseia, então não vejo como a leitura de um tutorial ajuda nesse sentido.
Bartek Banachewicz

Respostas:


163

Às vezes, é muito conveniente usar stringstream para converter entre strings e outros tipos numéricos. O uso de stringstreamé semelhante ao uso de iostream, portanto, não é um fardo aprender.

Stringstreams podem ser usados ​​para ler strings e gravar dados em strings. Funciona principalmente com um buffer de string, mas sem um canal de E / S real.

As funções-membro básicas da classe stringstream são

  • str(), que retorna o conteúdo de seu buffer no tipo string.

  • str(string), que define o conteúdo do buffer para o argumento string.

Aqui está um exemplo de como usar streams de string.

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

O resultado é dec: 15 hex: f.

istringstream tem mais ou menos o mesmo uso.

Para resumir, stringstream é uma maneira conveniente de manipular strings como um dispositivo de E / S independente .

Para sua informação, as relações de herança entre as classes são:

classes stream stream


19

Para responder à pergunta. stringstreambasicamente permite que você trate um stringobjeto como um streame use todas as streamfunções e operadores nele.

Eu vi que é usado principalmente para a qualidade de saída / entrada formatada.

Um bom exemplo seria a c++implementação da conversão de número em objeto de fluxo.

Exemplo possível:

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

Talvez seja um pouco complicado, mas é bastante complexo. Você cria um stringstreamobjeto ss, modifica seus sinalizadores, coloca um número nele com operator<<e o extrai via str(). Eu acho que isso operator>>poderia ser usado.

Também neste exemplo, o stringbuffer está oculto e não é usado explicitamente. Mas seria uma postagem muito longa para escrever sobre todos os aspectos e casos de uso possíveis.

Nota: Provavelmente roubei de alguém no SO e refinei, mas não tenho o autor original mencionado.


3
Nota: o uso de reté desnecessário, pode-se escrever return ss.str();.
Matthieu M.

@MatthieuM. Acho que não tinha certeza se RVO seria ativado se fosse escrito assim, ou se o objeto retornado por ss.str () sobreviveria ao ponto de saída. Assim, sei que estou fazendo uma cópia e o RVO funcionará. Mas você provavelmente está certo.
luk32

Na verdade, existem 2 formas de RVO: URVO (para não nomeado, ou seja, temporário) e NRVO (para nomeado); a maioria dos compiladores implementa RVO, mas alguns o restringem apenas a URVO (dependendo das opções de construção). Em geral, porém, há muitos outros fatores a serem levados em consideração, então você deve apenas escrever o código mais limpo possível e não se preocupar muito se o RVO entrará em ação.
Matthieu M.

NRVO é comum (assim como URVO), no entanto, não é um problema devido a mover os construtores.
Rapptz de

18

Do C ++ Primer :

O tipo istringstream lê uma string , ostringstream escreve uma string e o stringstream lê e escreve a string .

Encontrei alguns casos em que é conveniente e conciso usar stringstream .

caso 1

É de uma das soluções para este problema de leetcode . Ele demonstra um caso muito adequado em que o uso de stringstream é eficiente e conciso.

Suponha que ae bsejam números complexos expressos em formato de string, queremos obter o resultado da multiplicação de ae btambém no formato de string. O código é o seguinte:

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

Também é devido a um problema de leetcode que exige que você simplifique a string de caminho fornecida, uma das soluções usando stringstream é a mais elegante que já vi:

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

Sem o uso de stringstream, seria difícil escrever um código tão conciso.


2

Você inseriu um alfanumérico e inteiro, delimitado em branco por mystr.

Em seguida, você tentou converter o primeiro token (delimitado em branco) em um int.

O primeiro token foi RS que falhou na conversão para int, deixando um zero para myprice, e todos nós sabemos quanto zero vezes qualquer coisa rende.

Quando você inseriu apenas valores int na segunda vez, tudo funcionou conforme o esperado.

Foi o RS espúrio que causou a falha do seu código.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.