Um stream que vive em uma string
Você já conhece cin e cout - streams ligados ao teclado e à tela. Um stream de string é a mesma ideia, exceto que os dados vivem em uma std::string na memória. Você escreve nele com << e extrai valores com >>, exatamente como nos streams do console, mas nada toca o terminal.
Essa única ideia resolve dois problemas do dia a dia: analisar texto, separando-o em valores tipados, e construir uma string formatada a partir de pedaços misturados. Tudo vive no cabeçalho <sstream> e vem em três variações:
istringstream- somente leitura, para analisar entrada.ostringstream- somente escrita, para construir saída.stringstream- nas duas direções.
ss.str() retorna tudo o que foi escrito até agora como uma string simples. Os operadores << fizeram a mesma formatação de int para texto que o cout faz - você apenas capturou o resultado em vez de imprimi-lo.
Análise: extrair valores tipados
O verdadeiro poder aparece com >>. Forneça algum texto a um stream e a extração converte cada token para o tipo que você pedir, pulando os espaços em branco entre eles. Esta é a maneira limpa de quebrar uma linha em vários campos tipados:
Cada >> lê até o próximo espaço em branco e converte: "Ada" em uma string, "36" em um int, "5.5" em um double. Repare no istringstream aqui - o tipo somente de entrada deixa claro que você está apenas analisando.
Convertendo strings em números (com segurança)
Uma tarefa frequente é transformar uma única string como "42" em um int. Um stringstream faz isso e informa se o texto era realmente um número válido - algo que atoi nunca faz:
Aqui ss >> value lê 123, para no a e tem sucesso - então sempre valide a string inteira se isso for importante. Uma verificação robusta é ler o número e depois confirmar que nada significativo sobrou. Para conversões simples de valor único, std::stoi, std::stod e companhia (explicados junto com a conversão de tipos) são mais curtos; recorra ao stringstream quando uma string carregar vários valores misturados.
Dividindo uma string por um delimitador
Dividir texto é a tarefa de stream de string mais buscada no Google. Combine um stream com std::getline, que pode ler até qualquer caractere delimitador, não apenas uma quebra de linha:
O padrão while (getline(...)) repete até o stream se esgotar, porque getline retorna o stream e o stream é avaliado como false quando não sobra nada. Remova o terceiro argumento e você dividirá por tokens separados por espaços com >> - escolha o delimitador que seus dados usam.
Construindo strings na memória
No caminho inverso, ostringstream monta uma string formatada sem o risco de estouro de buffer do sprintf nem a frágil concatenação manual. É perfeito para linhas de log, nomes de arquivo ou mensagens montadas a partir de números e texto:
Toda a formatação de <iomanip> que você usaria com cout - setw, setfill, setprecision, hex - funciona de forma idêntica em um stream de string, então você obtém saída preenchida, de largura fixa ou em hexadecimal capturada diretamente em uma string.
A pegadinha: reinicie antes de reutilizar
A armadilha que pega todo mundo é reutilizar um stream sem reiniciá-lo. Quando um stream chega ao fim de seus dados, suas flags eof e fail ficam travadas, e todo >> posterior não faz nada silenciosamente - sem erro, apenas valores obsoletos:
stringstream ss("10");
int a, b;
ss >> a; // a = 10, o stream agora no fim -> flag eof ativada
ss.str("20"); // carrega novo texto...
ss >> b; // FALHA SILENCIOSAMENTE - as flags de erro ainda estão ativas, b não muda
Você precisa limpar o estado de erro e o conteúdo. A ordem correta é clear() primeiro, depois str():
Dois erros relacionados: ss.clear() reinicia as flags mas não esvazia o buffer (use ss.str("") para isso), e um stringstream ao qual você continua acrescentando com << vai continuar crescendo - crie um novo dentro do laço em vez de reutilizar um sujo a cada iteração.
A seguir: Arrays
Os streams de string lhe deram uma forma limpa de transformar texto em valores tipados e de volta - muitas vezes uma lista inteira deles, como o vector que você preencheu ao dividir o CSV. Para armazenar e indexar coleções fixas desses valores, você precisa do container mais fundamental da linguagem. A seguir veremos os arrays: como declará-los, indexá-los, percorrê-los e evitar o acesso fora dos limites que causa tanto comportamento indefinido em C++.
Perguntas frequentes
O que é um stringstream em C++?
Um std::stringstream é um stream apoiado por uma string em vez do teclado ou de um arquivo. Você escreve nele com << e lê dele com >>, exatamente como cout e cin, o que o torna a ferramenta padrão para analisar texto e construir strings na memória. Ele fica no cabeçalho <sstream>.
Como converter uma string em int em C++ com stringstream?
Coloque o texto em um stream e extraia para um número: stringstream ss("42"); int n; ss >> n;. Verifique if (ss) (ou if (ss >> n)) para confirmar que a conversão realmente deu certo. Para casos simples, std::stoi é mais curto, mas stringstream se destaca quando uma única string contém vários valores misturados.
Por que preciso chamar clear() em um stringstream?
Quando um stream chega ao fim de seus dados, seus bits eof/fail ficam ativos e todo >> seguinte não faz nada silenciosamente. Se você reutilizar o mesmo stringstream com conteúdo novo, chame ss.clear() para redefinir essas flags de erro e depois ss.str(newText) para carregar dados novos; caso contrário, as leituras falham sem aviso.