2012-07-07 12 views
7

Buscando en algún código antiguo que tenemos un montón de cosas como la siguiente:¿Puede un stringstream arrojar una excepción al leer un primitivo?

// This is dumb 
string do_something(int in) 
{ 
    stringstream out; 
    try 
    { 
     out << std::fixed << in; 
    } 
    catch(std::exception &e) 
    { 
     out << e.what(); 
    } 

    return out.str(); 
} 

// Can't we just do this? Can this ever fail? 
string do_something_better(int in) 
{ 
    stringstream out; 
    out << std::fixed << in; 
    return out.str(); 
} 

Cuando un stringstream lee una primitiva puede jamás lanzar una excepción? ¿Qué tal cuando lees una cadena?

+11

Ese código es una locura.Está detectando un error provocado por la transmisión y luego usa ** la misma transmisión ** para intentar comunicar ese error. Peor aún, está ensuciando su código de bajo nivel con un manejo de excepciones completamente sin sentido que no hace nada para * recuperar * del error, dejando el flujo en un estado roto. Debería detectar estos errores en un nivel en el que puede * hacer * algo acerca de ellos, incluso si solo está alertando al usuario y cancelando el programa. Este es un abuso completo del manejo de excepciones. – meagar

+0

Puede lanzar excepciones, pero solo si las ha habilitado llamando 'out.exceptions (selected_exceptions)'. Una secuencia construida por defecto no arroja excepciones (excepto 'bad_alloc', que difícilmente puede manejar aquí). –

+0

Puedes manejar totalmente 'bad_alloc'. Solo libera un montón de memoria. –

Respuesta

7

Resumiendo algunas respuestas

Por defecto, las corrientes no generen excepciones. Pueden si están habilitados.

stringstream out; 
out.exceptions(std::ios::failbit); // throw exception if failbit gets set 

Según el std Apache C++ Standard Library User's Guide

La bandera :: ios_base :: badbit indica problemas con el búfer de la secuencia subyacente. Estos problemas podrían ser:

Carencia de memoria. No hay memoria disponible para crear el búfer, o el búfer tiene el tamaño 0 por otros motivos (como que se proporciona desde fuera de la secuencia), o la secuencia no puede asignar memoria para sus propios datos internos, como con std :: ios_base :: iword() y std :: ios_base :: pword().

El almacenamiento intermedio de transmisión subyacente arroja una excepción. El almacenamiento intermedio de transmisión puede perder su integridad, como falta de memoria o error de conversión de código, o un error de lectura irrecuperable del dispositivo externo. El almacenamiento intermedio de flujo puede indicar esta pérdida de integridad lanzando una excepción, que es captada por el flujo y da como resultado el establecimiento del badbit en el estado del flujo.

Generalmente, debe tener en cuenta que el badbit indica una situación de error que es probable que sea irrecuperable, mientras que el error indica una situación que podría permitirle volver a intentar la operación fallida.

así que parece que la forma más segura de hacer esto sería

string do_something(int in) 
{ 
    stringstream out; // This could throw a bad_alloc 
    out << std::fixed << in; // This could set bad or fail bits 

    if(out.good()) 
    { 
     return out.str(); 
    } 
    else 
    { 
     return ""; 
    } 
} 

Ésta es una exageración, porque aunque de acuerdo a Handling bad_alloc si la creación de la corriente de falla, hay problemas más grandes de las que preocuparse, y el programa probablemente va a salir. Entonces, suponiendo que pasa la creación de la transmisión, es posible pero muy poco probable que se establezca el badbit. (El flujo se asigna con la memoria < sizeof (int)).

Tampoco es probable que se establezca el failbit (no estoy seguro de un caso de uso para leer la pila que no sea una pila corrupta). Por lo tanto, el siguiente código es suficiente, ya que la recuperación de un error de transmisión en este momento es poco probable.

string do_something(int in) 
{ 
    stringstream out; 
    out << std::fixed << in; 
    return out.str(); 
} 
2

Todas las transmisiones, incluido istringstreams, pueden arrojar excepciones (controlables con ios::exceptions) al leer, por ejemplo. cuando se agoten las entradas. Además, pueden lanzar cuando se está quedando sin memoria (por ejemplo, al construir la secuencia actualmente leída).

Su ejemplo de código, sin embargo, realiza escritura (?) La escritura AFAIK y int no debe producir ninguna excepción, aparte de los obvios errores de memoria (que su código no maneja muy bien).

Cuestiones relacionadas