Impostazione del buffer interno utilizzato da un stream standard (pubsetbuf)

Sto scrivendo una subroutine che ha bisogno di scrivere dati su un buffer esistente e vorrei usare la class stringstream per facilitare la formattazione dei dati.

Inizialmente, ho usato il seguente codice per copiare il contenuto del stream nel buffer, ma vorrei evitare questa soluzione poiché copia troppo di dati.

 #include  #include  void FillBuffer(char* buffer, unsigned int size) { std::stringstream message; message << "Hello" << std::endl; message << "World!" << std::endl; std::string messageText(message.str()); std::copy(messageText.begin(), messageText.end(), buffer); } 

Questo è quando ho scoperto il metodo streambuf::pubsetbuf() e ho semplicemente riscritto il codice di cui sopra come segue.

 #include  void FillBuffer(char* buffer, unsigned int size) { std::stringstream message; message.rdbuf()->pubsetbuf(buffer, size); message << "Hello" << std::endl; message << "World!" << std::endl; } 

Sfortunatamente, questo non funziona con l’implementazione della libreria standard C ++ fornita con Visual Studio 2008; buffer rimane invariato.

Ho esaminato l’implementazione di pubsetbuf e si scopre che letteralmente “non fa nulla”.

 virtual _Myt *__CLR_OR_THIS_CALL setbuf(_Elem *, streamsize) { // offer buffer to external agent (do nothing) return (this); } 

Questa sembra essere una limitazione dell’implementazione della libreria standard C ++ fornita. Qual è il modo consigliato di configurare un stream per scrivere il suo contenuto in un determinato buffer?

Dopo ulteriori ricerche su questo problema e il controllo del mio codice, mi sono imbattuto in un post che suggeriva l’uso di una class std::streambuf codificata a mano. L’idea alla base di questo codice è creare uno streambuf che inizializzi i suoi interni per fare riferimento al buffer specificato. Il codice è il seguente.

 #include  template  struct ostreambuf : public std::basic_streambuf > { ostreambuf(char_type* buffer, std::streamsize bufferLength) { // set the "put" pointer the start of the buffer and record it's length. setp(buffer, buffer + bufferLength); } }; 

Ora, se guardi il mio codice originale , noterai che non avevo davvero bisogno di un stringstream per cominciare. Tutto ciò di cui avevo veramente bisogno era un modo per scrivere su un buffer esterno usando la libreria IOStream e std::ostream è un tipo molto migliore per risolvere questo problema. Per inciso, ho il sospetto che questo è il modo in cui il tipo array_sink di Boost.IOStreams è implementato.

Ecco il codice modificato che usa il mio tipo ostreambuf .

 #include  #include "ostreambuf.h" // file including ostreambuf struct from above. void FillBuffer(char* buffer, unsigned int size) { ostreambuf ostreamBuffer(buffer, size); std::ostream messageStream(&ostreamBuffer); messageStream < < "Hello" << std::endl; messageStream << "World!" << std::endl; } 

Sembra un lavoro per lo std :: strstream (ufficialmente deprecato, ma ancora standard). In particolare, puoi anche guardare la libreria Boost.IOStreams , array_sink .

Come il link che hai postato dice: “le implementazioni specifiche possono variare”.

Non puoi semplicemente restituire l’object std :: string e quindi usare std :: string :: c_str () o std :: string :: data () nel punto in cui è richiesto il char buffer?

In alternativa, usa sprintf () dalla libreria C, quindi l’intera operazione può essere completata nel buffer passato. Poiché in questo modo si può verificare un potenziale sovraccarico del buffer e si utilizza Visual C ++, è ansible prendere in considerazione sprintf_s