2012-07-07 9 views
7

Guardando alcune vecchio codice abbiamo un sacco di cose come la seguente:Un stringente può generare un'eccezione durante la lettura di una primitiva?

// 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(); 
} 

Quando uno stringstream legge un primitivo può mai generare un'eccezione? Che dire quando si legge una stringa?

+11

Questo codice è folle.Stai rilevando un errore generato dallo stream e quindi utilizzi lo ** stesso ** stream per provare a comunicare tale errore. Peggio ancora, stai ingombrando il tuo codice di basso livello con una gestione delle eccezioni completamente priva di significato che non fa nulla per * recuperare * dall'errore, lasciando il flusso in uno stato di errore. Dovresti prendere questi errori a un livello in cui puoi * fare * qualcosa su di loro, anche se è solo avvisare l'utente e interrompere il programma. Questo è un abuso completo della gestione delle eccezioni. – meagar

+0

Può generare eccezioni, ma solo se le hai abilitate chiamando 'out.exceptions (selected_exceptions)'. Un flusso predefinito costruito non genera eccezioni (eccetto 'bad_alloc', che difficilmente si può gestire qui). –

+0

Puoi gestire completamente 'bad_alloc'. Basta liberare un po 'di memoria. –

risposta

7

Riassumendo alcune risposte

Per impostazione predefinita, i flussi non gettare eccezioni. Possono se sono abilitati.

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

Secondo la Apache C++ Standard Library User's Guide

Il flag std :: ios_base :: badbit indica problemi con il buffer di flusso sottostante. Questi problemi potrebbero essere:

Mancanza di memoria. Non c'è memoria disponibile per creare il buffer, o il buffer ha dimensione 0 per altri motivi (come essere fornito al di fuori del flusso), o il flusso non può allocare memoria per i propri dati interni, come con std :: ios_base :: iword() e std :: ios_base :: pword().

Il buffer del flusso sottostante genera un'eccezione. Il buffer del flusso potrebbe perdere la sua integrità, come in caso di esaurimento della memoria o di conversione del codice, o un errore di lettura irrecuperabile dal dispositivo esterno. Il buffer del flusso può indicare questa perdita di integrità generando un'eccezione, che viene catturata dal flusso e che determina l'impostazione del badbit nello stato del flusso.

In genere, è necessario tenere presente che badbit indica una situazione di errore che potrebbe non essere recuperabile, mentre failbit indica una situazione che potrebbe consentire di riprovare l'operazione non riuscita.

Così sembra che il modo più sicuro per fare questo sarebbe

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 ""; 
    } 
} 

questo è eccessivo, però, perché in base alle Handling bad_alloc se creare il flusso non riesce, ci sono problemi più grandi di cui preoccuparsi, e il programma probabilmente sta per uscire. Quindi, supponendo che passi oltre la creazione del flusso, è possibile ma estremamente improbabile che venga impostato il badbit. (Il flusso viene allocato con la memoria < sizeof (int)).

È anche improbabile che venga impostato il failbit (non è sicuro di un caso d'uso per la lettura dello stack diverso da uno stack corrotto). Quindi il seguente codice è sufficiente, in quanto il recupero da un errore di flusso a questo punto non è corretto.

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

Tutti i flussi, incluso istringstreams, possono generare eccezioni (controllabili con ios::exceptions) alla lettura, ad es. quando finiscono gli input. Inoltre possono lanciare quando esauriscono la memoria (ad esempio durante la costruzione della stringa attualmente letta).

L'esempio di codice, tuttavia, esegue la scrittura (?) Della scrittura AFAIK e int non dovrebbe produrre eccezioni, a parte gli errori ovvi di memoria (che il codice non gestisce molto bene).