2011-11-02 8 views
7

Me preguntaba si Boost.Format admite el uso de un búfer de ancho fijo/preasignado como salida en lugar de un búfer dinámico administrado por la lib misma.¿Es posible usar Boost.Format con un búfer preasignado?

Eso es, normalmente harías:

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

por lo que el Boost: lib formato será automáticamente se encargará de asignar espacio suficiente y la gestión de la "memoria intermedia de salida" para usted.

Me preguntaba si hay alguna manera de usar un tampón predefinido no dinámica con Boost.Format, es decir, algo así como:

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 

Sé que sólo pudiera tamizar a través de los ejemplos, los documentos y la fuente, pero aparte de carecer de tiempo atm. (y la posibilidad de perder algo) sería interesante saber: Si no es posible, sería genial si alguien pudiera explicar por qué (si hay/hay por qué), ¿fue deliberado? no coincide bien con la API? ...?

Descargo de responsabilidad: ¡Esta pregunta es no sobre el rendimiento!

+0

¿Qué desea que suceda cuando se queda sin espacio? Para un buff fijo usaría snprintf, pero ese soy yo :) – nhed

+0

@nhed Si no encaja, la biblioteca puede/podría lanzar una excepción o simplemente dejar de llenar el búfer (similar a [las opciones] (http://www.boost.org/doc/libs/1_47_0/libs/format/doc/format.html#exceptions) ya disponible) –

+0

No estoy seguro de que esas excepciones se apliquen al almacenamiento intermedio de destino – nhed

Respuesta

4

idea inicial

Mirando el source parece que se puede utilizar su propio asignador que luego se utiliza por la corriente interna (internal_streambuf_t) de boost::format. ¿Sería eso lo suficientemente bueno para su caso?

Por ejemplo, podría usar algo como el libstdC++ array_allocator

Desafortunadamente boost::format también utiliza un par de std::vector que no utilizan el asignador de costumbre que puede ser un problema en su caso?

cómo funciona boost::format

Miré en la fuente de boost::format y esto es ¿Cómo funciona (descrito a continuación es str(), << llamadas ya sea str() o utiliza el estándar std::ostream cosas):

  • la clase de formato almacena todos los argumentos y formatea cadena por separado, a veces usando el asignador personalizado, a veces usando el asignador predeterminado
  • cuando str() se llama cr eates un nuevo std::string y hace que sea lo suficientemente grande para que el resultado utilizando el asignador de costumbre
  • se anexa entonces todos los argumentos y pedazos de cuerda estática de la cadena de formato a la cadena de resultado
  • finalmente devuelve la cadena resultado por valor

Por lo tanto, la cadena de resultados final no se almacena dentro de la clase de formato, sino que se crea cuando es necesario.

Entonces, incluso si puede encontrar la ubicación de la cadena de resultados cuando usa un asignador personalizado, solo está disponible después de/durante una llamada al str(). Esto debería explicar por qué no es posible: el resultado formateado nunca se almacena dentro de un "búfer de salida" en la clase.

Por qué funciona así

por qué lo hicieron así que no sé. Creo que es porque solo puedes construir el resultado después de que se conocen todos los argumentos, se desperdicia espacio para almacenar el resultado y probablemente solo necesites el resultado una vez para una combinación determinada de formato/argumento. Por lo tanto, crearlo cuando sea necesario no genera trabajo adicional, ya que normalmente solo se llama a str() una vez.

Soluciones

  • crear un poco de envoltura alrededor de str() o << y copia el resultado en su memoria intermedia fija
  • Usar un (ejemplo véase más adelante) stream_buffer a 'flujo' de la cadena en el búfer
  • Heredar la clase y agregue su propia función str() que almacena el resultado en un búfer fijo.

Posible solución usando boost::iostreams (probado):

#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

Información útil. Creo que un pequeño problema con los asignadores es que solo pueden informar el error a través de bad_alloc, ¿correcto? –

+0

@Martin: creo que tienes razón. Además, investigué la fuente del formato y creo que usar un asignador es difícil de hacer. He actualizado mi respuesta con las cosas que encontré. – rve

+0

¡Buen trabajo! ¿Te entiendo correctamente: la cadena de salida se reconstruye cada vez que se llama a '.str()'? –

Cuestiones relacionadas