2009-08-15 15 views
15

Hay una tonelada de información disponible sobre la sobrecarga de operator<< para imitar un método de estilo toString() que convierte un objeto complejo en una cadena. Estoy interesado en también implementando el inverso, operator>> para deserializar una cadena en un objeto.Operador de secuencia de sobrecarga segura >>

Mediante la inspección de la fuente STL, que he reunido que:

istream &operator>>(istream &, Object &); 

sería la firma de la función correcta para deserializar un objeto de tipo Object. Desafortunadamente, no he encontrado la forma de implementarlo correctamente, específicamente cómo manejar los errores:

  1. ¿Cómo indicar datos no válidos en la secuencia? Lanzar una excepción?
  2. ¿En qué estado debe estar la transmisión si es datos mal formados en la secuencia?
  3. ¿Deben restablecerse los indicadores antes de devolver la referencia para el encadenamiento del operador?

Respuesta

18
  1. ¿Cómo indicar datos no válidos en la corriente? Lanzar una excepción?

Debe establecer el bit fail. Si el usuario de la transmisión quiere lanzar una excepción, puede configurar la transmisión (usando istream::exceptions), y la transmisión arrojará en consecuencia. Me gustaría hacerlo de esta manera, entonces

stream.setstate(ios_base::failbit); 
  1. ¿En qué estado debe estar en la corriente si hay datos mal formados en la corriente?

Para los datos incorrectos que no se ajustan al formato que desea leer, generalmente debe establecer el bit fail. Para los errores específicos de la secuencia interna, se utiliza el bit bad (como, por ejemplo, si no hay un búfer conectado a la transmisión).

  1. ¿Deben reiniciarse los indicadores antes de devolver la referencia para el encadenamiento del operador?

No he oído hablar de tal cosa.


Para comprobar si la corriente está en un buen estado, puede utilizar la clase istream::sentry. Cree un objeto, pase la secuencia y true (para decirle que no salte espacios en blanco inmediatamente). El centinela evaluará a false si está configurado el bit eof, fail o bad.

istream::sentry s(stream, true); 
if(!s) return stream; 
// now, go on extracting data... 
+1

También asegúrese de marcar el bit 'fail' antes de intentar hacer algo. Si ya está configurado, simplemente devuelve la transmisión. – KTC

+1

Gracias por el consejo, especialmente al usar el bit 'fail' en lugar de excepciones. Además de establecer el bit de falla, ¿debo hacer alguna garantía sobre el contenido de la transmisión? Por ejemplo, ¿la transmisión no se modificará si configuro el bit 'fail'? –

+0

Eso es esencialmente lo que iba a decir, ¡pero respondiste más rápido! Añadiría que la respuesta correcta se encuentra buscando qué hacen las implementaciones existentes, que es lo que estás describiendo. Además, señalaría que no existe información mal formada, sino un formato incorrecto para leerla; en ese caso, quiere asegurarse de que la variable no se modifique, y (si establece el bit de falla y no el bit malo) que no se han perdido caracteres de la secuencia. –

0

En cuanto a las banderas, no sé si hay algún estándar en alguna parte, pero es una buena idea restablecerlas.

Boost tiene envolturas Raii ordenadas para ello: IO State Savers

+0

No creo que esto esté diseñado para ser utilizado en extractores, sino por código de usuario. – AProgrammer

+0

No veo la diferencia. También funcionan en las transmisiones de entrada, por lo que si desea establecer la bandera como lo que era, mejor que manualmente de todos modos.El extractor que afecta la transmisión de forma extraña está esencialmente roto. – Eugene

2

Algunas notas adicionales:

  • la hora de aplicar el operador >>, probablemente debería considerar el uso de la bufstream y no otras sobrecargas de operador> >;

  • excepciones que ocurren durante la operación deben ser traducidos a la failbit o la badbit (miembros de streambuf pueden tirar, dependiendo de la clase utilizado);

  • configurando el estado puede arrojar; si configura el estado después de capturar una excepción , debe propagar la excepción original y no la que lanzó por setstate;

  • el ancho es un campo al que debe prestar atención. Si tiene tomándolo en cuenta, debe restablecerlo a 0. Si está utilizando otro operador >> para realizar trabajos básicos, debe calcular el ancho que está pasando del que recibió;

  • considere tener en cuenta la configuración regional.

Lange y Kreft (estándar de C++ iostreams y Locales) conver esto en incluso más detalles. Proporcionan un código de plantilla para el manejo de errores que toma aproximadamente una página.

+0

¿Por qué sugieres usar 'bustream' en lugar de otras sobrecargas (por ejemplo,' istream'? Me aseguraré de revisar el trabajo de Lange and Kreft, suena exactamente como lo que estoy buscando. –