Como reutilizar um ostringstream?

Respostas:

156

Eu usei uma sequência de clear e str no passado:

// clear, because eof or other bits may be still set. 
s.clear();
s.str("");

O que funcionou para os streams de entrada e de saída. Como alternativa, você pode limpar manualmente e, em seguida, buscar a sequência apropriada para o início:

s.clear();
s.seekp(0); // for outputs: seek put ptr to start
s.seekg(0); // for inputs: seek get ptr to start

Isso evitará algumas realocações feitas strsobrescrevendo o que quer que esteja no buffer de saída atualmente. Os resultados são assim:

std::ostringstream s;
s << "hello";
s.seekp(0);
s << "b";
assert(s.str() == "bello");

Se você quiser usar a string para funções c, você pode usar std::ends, colocando um nulo de terminação como este:

std::ostringstream s;
s << "hello";
s.seekp(0);
s << "b" << std::ends;
assert(s.str().size() == 5 && std::strlen(s.str().data()) == 1);

std::endsé uma relíquia do obsoleto std::strstream, que foi capaz de gravar diretamente em uma matriz char que você alocou na pilha. Você teve que inserir um nulo de terminação manualmente. No entanto, std::endsnão está obsoleto, acho que é porque ainda é útil como nos casos acima.

Johannes Schaub - litb
fonte
Estou tentando usar s.str () com um ostream. O tamanho está bagunçando tudo (posso ver que o primeiro caractere é nulo, mas imprime muito mais). Existe uma boa maneira de corrigir o comprimento do str? estou usando s.str (). c_str (); ATM e funciona bem
Na verdade, mesmo isso não é correto. Eu apenas fiz em s.str("");vez disso. auto str = s.str(); auto cstr = str.c_str(); file << cstr; s.clear(); s.seekp(0); s << ends;
o std :: ends não funciona para mim no teste do Google boost::any a = 1; std::ostringstream buffer; buffer << a << std::ends; EXPECT_EQ( buffer.str(), "any<(int)1>" ); TestUtilsTest.cpp:27: Failure Expected: buffer.str() Which is: "any<(int)1>\0" To be equal to: "any<(int)1>" e se eu reutilizar strings de comprimento diferente, fico com os bits restantes
David van Laatum
A alternativa é a verdadeira resposta se você quiser evitar a realocação. E se você quiser realmente "começar do zero" sem realocação, apenas chame seekp (0) novamente após enviar std :: end. s.seekp(0); s << std::ends; s.seekp(0);
Chip Grandits
5

Parece que a ostr.str("")ligação resolve.

Diego sevilla
fonte
9
Vale ressaltar que isso não vai reutilizar o buffer subjacente do ostringstream - apenas atribui um novo buffer. Portanto, enquanto você reutiliza o objeto ostringstream, ainda está alocando dois buffers. Não acho que ostringstream foi projetado para ser reutilizado da maneira que você pretende.
razlebe
2
Também não limpa o estado, que é o que .clear () faz. Eu concordo, realmente não é para ser usado assim. Basta criar um novo para ter certeza. Somente se você fizer o perfil, você saberá se isso faz alguma diferença.
Brian Neal,
1
sgreeve, Brian, isso mesmo. Observe, entretanto, como o método do litb acima requer o uso de std :: ends. Ele reutiliza o buffer, mas faz com que você codifique de forma diferente, como de costume com stringstreams (normalmente você não usa std :: ends).
Diego Sevilla,
2

Se você pretende limpar o buffer de uma forma que fará com que ele seja limpo antes de seu primeiro uso, você precisará adicionar algo ao buffer primeiro com MSVC.

struct Foo {
    std::ostringstream d_str;
    Foo() { 
        d_str << std::ends;   // Add this
    }
    void StrFunc(const char *);
    template<class T>
    inline void StrIt(const T &value) {
        d_str.clear();
        d_str.seekp(0);  // Or else you'll get an error with this seek
        d_str << value << std::ends;
        StrFunc(d_str.str().c_str());  // And your string will be empty
    }
};
George Unkle
fonte
Não estou vendo o comportamento de falha no VS2012. Além disso, a chamada clearfará com que o failbitseja definido se o fluxo estiver vazio. Embora apenas a chamada seekpdeva simplesmente retornar se nenhum stream existir.
Jonathan Mee
0

Você não. Use dois fluxos com nomes diferentes para maior clareza e deixe o compilador de otimização descobrir que pode reutilizar o antigo.

Sebastian Ganslandt
fonte
4
considere o caso de uso em que o código está em loop sobre os dados de entrada, escrevendo em um ostringstream(com base nos dados lidos) e, em seguida, tem que escrever a string construída em ostringstreamalgum lugar de tempos em tempos (por exemplo, após uma certa sequência de caracteres ter sido lida) e começar construir uma nova string.
Andre Holzner