2011-11-02 12 views
7

Mi chiedevo se lo standard Boost.Format supporti l'utilizzo di un buffer a larghezza fissa/preallocato come output anziché un buffer dinamico gestito dalla stessa libreria di distribuzione?È possibile utilizzare Boost.Format con un buffer preallocato?

Che è, normalmente faresti:

boost::format myfmt("arg1: %1%/arg2: %2%"); 
// e.g.: 
cout << (myfmt % 3.14 % 42); 
// or 
string s = boost::str(myfmt % "hey!" % "there!"); 

in modo che il Boost: lib Format avrà automaticamente la cura di allocare abbastanza spazio e la gestione del "buffer di uscita" per voi.

Mi chiedevo se c'è un modo per utilizzare un buffer di predefinire non dinamico con Boost.Format, cioè, qualcosa di simile:

const size_t buf_sz = 512; 
char big_enough[buf_sz]; 
boost::format myfmt("arg1: %1%/arg2: %2%"); 
myfmt.attach_buffer(big_enough, buf_sz); 
myfmt % "hey!" % "there!" 
// big_enough buffer now contains the result string 

So che potrei appena setacciare gli esempi, la documentazione e la fonte, ma a parte la mancanza di tempo atm. (e la sola possibilità di perdere qualcosa) sarebbe interessante sapere: Se non è possibile, sarebbe bello se qualcuno potesse spiegare perché (se c'è/sono specifici perché) - è stato deliberato? non corrisponde bene all'API? ...?

Disclaimer: Questa domanda è non sulle prestazioni!

+0

Cosa vuoi che accada quando si esaurisce lo spazio? Per un buff fisso userei snprintf, ma quello sono io :) – nhed

+0

@nhed Se non va bene, la libreria può/può lanciare un'eccezione o semplicemente smettere di riempire il buffer (simile a [le opzioni] (http://www.boost.org/doc/libs/1_47_0/libs/format/doc/format.html#exceptions) già disponibile) –

+0

Non sono sicuro che tali eccezioni si applichino al buffer di destinazione – nhed

risposta

4

idea iniziale

Guardando il source sembra è possibile utilizzare il proprio allocatore che viene poi utilizzato dal flusso interno (internal_streambuf_t) di boost::format. Sarebbe abbastanza buono per il tuo caso?

Per esempio si potrebbe usare qualcosa come il libstdC++ array_allocator

Purtroppo boost::format usa anche un paio di std::vector che non utilizzano l'allocatore personalizzato che può essere un problema nel vostro caso?

come funziona boost::format

ho guardato dentro la fonte di boost::format e questo è come funziona (descritto di seguito è str(), << chiamate sia str() o utilizza lo standard std::ostream roba):

  • la classe di formato memorizza tutti gli argomenti e formatta la stringa separatamente, a volte utilizzando l'allocatore personalizzato, a volte utilizzando l'allocatore predefinito
  • quando str() viene chiamato esso cr eates un nuovo std::string e lo rende abbastanza grande per il risultato usando l'allocatore personalizzato
  • che quindi aggiunge tutti gli argomenti e pezzi di stringhe statiche dalla stringa di formato per la stringa risultante
  • finalmente ritorna la stringa risultato per valore

Quindi, la stringa del risultato finale non è memorizzata all'interno della classe di formato ma creata quando necessario.

Quindi, anche se è possibile trovare la posizione della stringa del risultato quando si utilizza un allocatore personalizzato, è disponibile solo dopo/durante una chiamata a str(). Questo dovrebbe spiegare perché non è possibile: il risultato formattato non viene mai memorizzato all'interno di un "buffer di output" nella classe.

perché funziona in questo modo

perché lo hanno fatto in questo modo non lo so. Penso che sia perché puoi costruire il risultato solo dopo che tutti gli argomenti sono noti, sprecando spazio per memorizzare il risultato e probabilmente hai solo bisogno del risultato solo una volta per una determinata combinazione formato/argomento. Quindi, la creazione quando necessario non comporta un lavoro aggiuntivo poiché in genere str() viene chiamato solo una volta.

Solutions

  • creare qualche wrapper str() o << e copiare il risultato nella buffer fisso
  • Utilizzare un stream_buffer a 'flusso' la stringa nel buffer (vedi esempio sotto)
  • Eredita la classe e aggiungere la propria funzione str() che memorizza il risultato in un buffer fisso.

Possibile soluzione utilizzando boost::iostreams (testato):

#include <iostream> 
#include <boost/format.hpp> 
#include <boost/iostreams/stream.hpp> 

int main() 
{ 
    char buffer[100]; 

    boost::iostreams::stream<boost::iostreams::array_sink> 
     stream(buffer, sizeof(buffer)); 

    stream << (boost::format("arg1 = %1%") % 12.5); 
    stream << '\0'; // make sure buffer contains 0-terminated string 

    std::cout << buffer << std::endl;  
} 
+0

Informazioni utili. Penso che un piccolo problema con gli allocatori sia che possono solo segnalare un errore tramite bad_alloc, corretto? –

+0

@ Martin: Penso che tu abbia ragione. Inoltre, ho esaminato la fonte del formato e penso che l'uso di un allocatore sia difficile da fare. Ho aggiornato la mia risposta con le cose che ho trovato. – rve

+0

Bel lavoro! Ho capito bene: la stringa di output viene ricostruita ogni volta che viene chiamato '.str()'? –

Problemi correlati