Come riutilizzare un ostringstream?


Risposte:


156

Ho usato una sequenza di clear e str in passato:

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

Che ha funzionato sia per gli stringstream di input che di output. In alternativa, puoi cancellare manualmente, quindi cercare la sequenza appropriata per iniziare:

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

Ciò eviterà alcune riallocazioni eseguite strsovrascrivendo invece ciò che è attualmente nel buffer di output. I risultati sono così:

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

Se vuoi usare la stringa per le funzioni c, puoi usare std::ends, mettendo un null di terminazione come questo:

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è un relitto del deprecato std::strstream, che era in grado di scrivere direttamente su un array di caratteri allocato nello stack. Dovevi inserire manualmente un null di terminazione. Tuttavia, std::endsnon è deprecato, penso perché è ancora utile come nei casi precedenti.


Sto cercando di usare s.str () con un ostream. La dimensione lo sta incasinando (posso vedere il primo carattere è nullo ma stampa molto di più). C'è un buon modo per correggere la lunghezza dello str? sto usando s.str (). c_str (); ATM e funziona bene

In realtà anche questo non è corretto. s.str("");Invece l' ho fatto . auto str = s.str(); auto cstr = str.c_str(); file << cstr; s.clear(); s.seekp(0); s << ends;

lo std :: finisce non funziona per me nel test di 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 riutilizzo con stringhe di lunghezza diversa mi rimangono dei bit
David van Laatum

L'alternativa è la vera risposta se vuoi evitare la riallocazione. E se vuoi veramente "ricominciare da capo" senza riallocazione, chiama di nuovo seekp (0) dopo aver inviato std :: end. s.seekp(0); s << std::ends; s.seekp(0);
Chip Grandits

5

Sembra che la ostr.str("")chiamata faccia il trucco.


9
Vale la pena sottolineare che questo non riutilizzerà il buffer sottostante dall'ostringstream, ma assegna solo un nuovo buffer. Quindi, mentre stai riutilizzando l'oggetto ostringstream, stai ancora allocando due buffer. Non penso che ostringstream sia progettato per essere riutilizzato nel modo in cui intendi.
razlebe

2
Inoltre non cancella lo stato, che è ciò che fa .clear (). Sono d'accordo, in realtà non è pensato per essere usato in questo modo. Creane uno nuovo per essere sicuro. Solo se profili scoprirai se fa differenza.
Brian Neal

1
sgreeve, Brian, è vero. Nota, tuttavia, come il metodo litb sopra richiede l'uso di std :: end. Riutilizza il buffer, ma ti fa scrivere codice in modo diverso come al solito con gli stringstream (normalmente non usi std :: End).
Diego Sevilla

2

Se hai intenzione di svuotare il buffer in un modo che lo farà cancellare prima del primo utilizzo, dovrai prima aggiungere qualcosa al buffer con 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
    }
};

Non vedo il comportamento fallito su VS2012. Inoltre, chiamando clearfarà causare il failbitessere impostata se il flusso è vuota. Mentre solo la chiamata seekpdovrebbe semplicemente tornare se non esiste alcun flusso.
Jonathan Mee

0

Non lo fai. Usa due flussi con nomi diversi per maggiore chiarezza e lascia che il compilatore di ottimizzazione capisca che può riutilizzare quello vecchio.


4
considera il caso d'uso in cui il codice esegue il loop sui dati di input, scrive su un ostringstream(in base ai dati letti) e poi deve scrivere la stringa costruita ostringstreamda qualche parte di volta in volta (ad esempio dopo che è stata letta una certa sequenza di caratteri) e iniziare costruire una nuova stringa.
Andre Holzner
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.