2010-04-01 9 views
9

Ein gemeinsames Stück Code, den ich für einfachen String Splitting verwenden sieht wie folgt aus:Ways std :: stringstream kann fail/bad bit setzen?

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

Jemand erwähnte, dass dies leise „schlucken“ Fehler in std::getline auftreten. Und natürlich stimme ich zu, dass das der Fall ist. Aber es kam mir in den Sinn, was könnte hier schief gehen in der Praxis, dass ich mir Sorgen machen müsste. im Grunde ist es läuft alles auf diese nach unten:

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

A stringstream wird von einem string gesichert, so dass wir nicht über keine der Probleme mit dem Lesen aus einer Datei zugeordnet kümmern. Hier findet keine Typumwandlung statt, da getline einfach gelesen wird, bis der Linienbegrenzer oder EOF angezeigt wird. So können wir keine der Fehler bekommen, über die sich etwas wie boost::lexical_cast Sorgen machen muss.

Ich kann einfach nicht an etwas denken, abgesehen davon, dass ich nicht genügend Speicher zuordnen kann, der schief gehen könnte, aber das wird einfach einen std::bad_alloc werfen, bevor die std::getline überhaupt stattfindet. Was vermisse ich?

+1

Was ist falsch ist die Rückgabe einer Referenz auf eine lokale. – UncleBens

+1

Guter Fang, obwohl ich nicht gemeint habe, einen Verweis auf einen lokalen zurückzugeben, ist dies ein reduziertes Beispiel, um die Grundlagen der Frage zu demonstrieren –

+1

Ein 'stringstream' wird nur dann von einem' string' unterstützt, wenn Sie nicht aufgerufen haben 'rdbuf (othertreambuf)'. –

Antwort

6

Ich kann mir nicht vorstellen, welche Fehler dieser Person passieren könnte, und Sie sollten sie bitten, zu erklären. Es kann nichts schief gehen, außer Zuordnungsfehlern, wie Sie erwähnt haben, die geworfen und nicht verschluckt werden.

Die einzige Sache, die ich sehe, die Sie direkt vermissen, ist, dass ss.fail() garantiert ist, nach der while-Schleife wahr zu sein, weil das die Bedingung ist, die geprüft wird. (bool(stream) ist äquivalent zu !stream.fail(), nichtstream.good().) Wie erwartet, ss.eof() wird auch wahr sein, anzeigend, dass der Fehler wegen EOF war.

Allerdings könnte es einige Verwirrung darüber geben, was tatsächlich passiert. Da getline verwendet delim - beendet Felder statt delim - getrennt Felder, Eingabedaten wie "a\nb\n" zwei statt drei Felder hat, und dies könnte überraschend sein. Für Zeilen ist dies völlig sinnvoll (und ist POSIX-Standard), aber wie viele Felder, mit einem Delim von '-', würden Sie erwarten, in "a-b-" nach dem Aufspalten zu finden?


Übrigens ist hier, wie ich würde 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; 
} 

Diese alle Probleme mit iostreams in erster Linie verhindert, vermeidet zusätzliche Kopien (die Trägersaite von string; plus die Temperatur zurück by substr kann sogar eine C++ 0x rvalue-Referenz für die Verschiebungssemantik verwenden, wenn sie unterstützt wird (wie geschrieben), hat das Verhalten, das ich von der Trennung erwarte (anders als deine) und arbeitet mit jedem Container.

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

guter Punkt über die Verwendung 's.fail()', ich nehme 's.bad()' wäre eine bessere Wahl? oder vielleicht '! s.eof()'? (Es sollte wegen EOF enden, also wenn es nicht EOF ist, dann ist es gescheitert, richtig?) –

+0

Auch ein guter Punkt über abgeschlossene vs getrennte Felder. Ich hatte nie zuvor ein Problem damit, aber ich konnte es als überraschend sehen. Ein Grund mehr, die Anzahl der Felder zu testen, bevor Sie Ihre Daten aus dem Ergebnis extrahieren. –

+0

@Evan: Identifizieren Sie zuerst die Bedingung, die Sie überprüfen möchten. Es besteht keine Notwendigkeit, nach der Schleife Fehler, Fehler, eof oder irgendwas anderes auf * ss * zu überprüfen, aber Sie sollten vielleicht * elems * überprüfen, wie Sie gesagt haben. –