2010-04-01 11 views
9

Una pieza común de código que utilizo para partir simple cadena tiene el siguiente aspecto:Ways std :: stringstream puede establecer un bit fallido/malo?

inline std::vector<std::string> split(const std::string &s, char delim) { 
    std::vector<std::string> elems; 
    std::stringstream ss(s); 
    std::string item; 
    while(std::getline(ss, item, delim)) { 
     elems.push_back(item); 
    } 
    return elems; 
} 

Alguien mencionó que este silencio se "golondrina" errores que ocurren en std::getline. Y, por supuesto, estoy de acuerdo con ese es el caso. Pero se me ocurrió, lo que podría salir mal aquí en la práctica que tendría que preocuparme. Básicamente todo se reduce a esto:

inline std::vector<std::string> split(const std::string &s, char delim) { 
    std::vector<std::string> elems; 
    std::stringstream ss(s); 
    std::string item; 
    while(std::getline(ss, item, delim)) { 
     elems.push_back(item); 
    } 

    if(/* what error can I catch here? */) { 
     // *** How did we get here!? *** 
    } 

    return elems; 
} 

Un stringstream está respaldado por una string, por lo que no tiene que preocuparse por ninguno de los problemas asociados con la lectura de un archivo. No hay conversión de tipo aquí desde que getline simplemente lee hasta que ve la línea delimeter o EOF. Así que no podemos obtener ninguno de los errores que algo así como boost::lexical_cast tiene que preocuparse.

Simplemente no puedo pensar en algo además de no asignar suficiente memoria que podría salir mal, pero eso arrojará un std::bad_alloc incluso antes de que el std::getline tenga lugar. ¿Qué me estoy perdiendo?

+1

Lo que está mal es devolver una referencia a un local. – UncleBens

+1

Buena captura, aunque no quise devolver una referencia a un local, este es un ejemplo reducido para demostrar los conceptos básicos de la pregunta –

+1

Un 'stringstream' está respaldado por una' cadena' solo si no ha llamado 'rdbuf (otherstreambuf)'. –

Respuesta

6

No me puedo imaginar qué errores cree que esta persona podría pasar, y deberías pedirles que te expliquen. Nada puede salir mal excepto los errores de asignación, como usted mencionó, que se lanzan y no se tragan.

Lo único que veo que falta directamente es que ss.fail() se garantiza que es verdadero después del ciclo while, porque esa es la condición que se está probando. (bool(stream) es equivalente a !stream.fail(), nostream.good()). Como se esperaba, ss.eof() también será verdadero, lo que indica que la falla se debió a EOF.

Sin embargo, puede haber cierta confusión sobre lo que realmente está sucediendo. Debido getline utiliza delim - terminado campos en lugar de delim - separados campos, los datos de entrada tales como "a\nb\n" tiene dos en vez de tres campos, y esto podría ser sorprendente. Para líneas esto tiene sentido completo (y es estándar POSIX), pero ¿cuántos campos, con un delim de '-', esperaría encontrar en "a-b-" después de la división?


Por cierto, aquí está cómo había writesplit:

template<class OutIter> 
OutIter split(std::string const& s, char delim, OutIter dest) { 
    std::string::size_type begin = 0, end; 
    while ((end = s.find(delim, begin)) != s.npos) { 
    *dest++ = s.substr(begin, end - begin); 
    begin = end + 1; 
    } 
    *dest++ = s.substr(begin); 
    return dest; 
} 

Esto evita todos los problemas con iostreams en primer lugar, evita copias adicionales (de cuerda respaldo del stringstream; además devolvió la temp por substr puede incluso usar una referencia de valor de C++ 0x para la semántica de movimiento si se admite, tal como está escrito), tiene el comportamiento que espero de la división (diferente del suyo), y funciona con cualquier contenedor.

deque<string> c; 
split("a-b-", '-', back_inserter(c)); 
// c == {"a", "b", ""} 
+0

buen punto sobre el uso 's.fail()', supongo 's.bad()' sería una mejor opción? o tal vez '! s.eof()'? (debe terminar debido a EOF, entonces, si no es EOF, ¿falló?) –

+0

Además, es un buen punto sobre los campos separados. Nunca tuve un problema con eso antes, pero pude ver que era sorprendente. Razón de más para probar el número de campos que obtuvo antes de extraer sus datos del resultado. –

+0

@Evan: Primero identifique la condición que está tratando de verificar. No hay necesidad de comprobar fail, bad, eof o cualquier otra cosa en * ss * después del bucle, pero es posible que desee comprobar * elems *, como ha dicho. –

Cuestiones relacionadas