Modi std :: stringstream può impostare sicuro / cattivo po '?
-
23-09-2019 - |
Domanda
Un comune pezzo di codice che utilizzo per semplici sguardi stringa spaccare in questo modo:
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;
}
Qualcuno ha detto che questo sarà silenziosamente "rondine" errori che si verificano in std::getline
. E, naturalmente, sono d'accordo che è il caso. Ma mi venne in mente, cosa potrebbe andare male qui in pratica che avrei avuto bisogno di cui preoccuparsi. in fondo tutto si riduce a questo:
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
è sostenuta da un string
, in modo da non devono preoccuparsi di nessuno dei problemi connessi con la lettura da un file. Non v'è alcuna conversione di tipo succedendo qui dal getline
legge semplicemente fino a che non vede il delimitatore di linea o EOF
. Quindi non siamo in grado di ottenere qualsiasi degli errori che qualcosa di simile boost::lexical_cast
deve preoccuparsi.
Ho semplicemente non può pensare a qualcosa oltre non riuscire a allocare memoria sufficiente che poteva andare storto, ma che ti basta gettare un std::bad_alloc
ben prima della std::getline
ancora avviene. Che cosa mi manca?
Soluzione
Non riesco a immaginare che cosa gli errori di questa persona pensa che potrebbe accadere, e si dovrebbe chiedere loro di spiegare. Nulla può andare storto, tranne gli errori di allocazione, come lei ha ricordato, che vengono gettati e non ingoiato.
L'unica cosa che vedo che si sta direttamente manca è che ss.fail()
è garantito per essere vero, dopo il ciclo while, perché questa è la condizione in fase di test. (bool(stream)
è equivalente a !stream.fail()
, non stream.good()
.) Come previsto, ss.eof()
sarà anche vero, indica un guasto era dovuto a EOF.
Tuttavia, ci potrebbe essere una certa confusione su ciò che sta realmente accadendo. Perché getline usi delim - terminati campi anziché delim - separato campi, ingresso dati come "a\nb\n"
ha due invece di tre campi, e questo potrebbe essere sorprendente. Per le linee questo senso completo (ed è standard POSIX), ma come molti campi, con una delim di '-'
, ci si può aspettare di trovare in "a-b-"
dopo la divisione?
Per inciso, ecco come avrei scrittura spaccatura :
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;
}
Questo evita tutti i problemi con iostreams, in primo luogo, evita copie extra (stringa di sostegno del stringstream, in più la temperatura restituito da substr può anche utilizzare un riferimento di C ++ 0x rvalue per la semantica mossa se supportata, come scritto) , ha il comportamento mi aspetto da split (diverso dal tuo), e funziona con qualsiasi contenitore.
deque<string> c;
split("a-b-", '-', back_inserter(c));
// c == {"a", "b", ""}