[Gelöst] User Defined Type aus istream auslesen schlägt fehl - weiß nicht warum
-
Hallo zusammen,
ich habe ein kleines Problem, dass bei mir aufgetreten ist, und ich kann mir dieses nicht erklären. Ich habe einen istream, mit folgendem Inhalt:
std::cout << is.rdbuf() << std::endl; // ergebnis: 3317454668 Test 480 80 2015-05-06 17:19:11Es ist auch wirklich genau so in der Konsole zu sehen.
Meine "Klasse" (eher ein struct) sieht so aus (unwichtiges ist entfernt, ich habe debugging statements eingefügt):
class Highscore { public: Highscore(); friend std::istream& operator>>(std::istream&, Highscore&); private: unsigned int score { 0 }; unsigned int time { 0 }; std::string name; unsigned int checksum { 0 }; std::string timestamp; }; // cpp Highscore::Highscore() : name {}, timestamp {} { } std::istream& operator>>(std::istream& is, Highscore& hs) { if (!is) std::cout << "received bad istream\n"; is >> hs.checksum; if (!is) std::cout << "checksum failed\n"; /* is >> hs.name; if (!is) std::cout << "name failed\n"; is >> hs.score; if (!is) std::cout << "score failed\n"; is >> hs.time; if (!is) std::cout << "time failed\n"; if (!is) return is; // so weit komme ich eh garnicht std::string date, time; is >> date >> time; std::cout << "date: " << date << " / time: " << time << std::endl; hs.timestamp = date + " " + time; if (hs.make_checksum() != hs.checksum) { is.clear(std::ios_base::failbit); return is; } */ return is; }Versuche ich nun das einlesen, steht das hier in meiner Konsole:
checksum failedEinlesen tue ich in etwa so:
Highscore hs; while (is >> hs) // ...Es scheint für mich also ersichtlich, dass das einlesen der ersten Zahl fehlschlägt.
Doch wieso? Ich kann es mir nicht erklären. Ich habe auch schon versucht nur die Zahl in einem eigenen main() einzulesen+auszugeben. Hat einwandfrei funktioniert. Und selbst wenn es zum Overflow kommen sollte, würde doch trotzdem der stream good bleiben, oder irre ich mich da?Nochmals, das hier hat funktioniert:
unsigned int foo = 0; cin >> foo; cout << foo;Konsole:
3317454668 3317454668Ich hoffe es gibt jemanden, der hier nicht genauso ratlos ist, und vielleicht eine Idee hat, woran das liegen könnte. Wie schon gesagt, ich bin da komplett raus, hab keine Ahnung wieso ich beim einen Mal den Uint einlesen kann und beim anderen Mal nicht.
-
Dass es das zweite mal fehlschlägt, ist klar (dann kommt EOF). Kannst du mal ein vollständiges Beispiel geben?
-
Und woher weisst Du jetzt genau, dass schon das einlesen der Zahl schiefläuft und die Ausgabe "checksum failed" nicht erst passiert, wenn der String "Test" im stream anliegt?
-
Ich glaube das aus 2 Gründen zu wissen:
1. Wenn ich das Auskommentierte laufen lasse (also auch versuche 'Test' und alles Andere einzulesen), komme ich trotzdem auf den gleichen Fehler, nur dass es halt dann so aussieht:checksum failed name failed score failed time failedWobei ja klar ist, dass alles Andere dann auch fehlschlägt.
2. Durch folgende Modifikation lässt sich das ebenfalls prüfen:
// ... private: std::size_t readCount{ 0 }; //... if (!is) std::cout << "received bad istream\n"; is >> hs.checksum; ++hs.readCount; if (!is) std::cout << "checksum failed at " << hs.readCount << ". time\n";checksum failed at 1. timewürde es die Zahl erfolgreich einlesen und beim 2. Mal bei 'Test' scheitern, stünde da mit großer Wahrscheinlichkeit
checksum failed at 2. timeAußerdem kann ich auch einfach versuchen nach dem Einlesen checksum auszugeben, was dann so aussieht:
if (!is) std::cout << "received bad istream\n"; is >> hs.checksum; std::cout << hs.checksum << std::endl; if (!is) std::cout << "checksum failed\n";0 checksum failedWas meiner Ansicht nach ebenfalls beweist, dass nie erfolgreich eingelesen wurde (checksum wird ja mit 0 initalisiert).
Ich bekomme es nicht hin, in einem minimalen Beispiel den Fehler zu reproduzieren. Da mache ich es aber auch mit einem stringstream. Hilft mir trotzdem nicht, das Problem zu finden.
Weitere kleine Infos: Wenn ich in der Zeile, die 'checksum' einließt einen breakpoint setzte, und "step-into" versuche, springt er trotzdem sofort in die nächste Zeile (ich bin es gewohnt, dass dann ein haufen Code mit _Bezeichnern kommt)
Ich muss garnicht über den >>-operator von Highscore gehen, um das Problem zu erzeugen. Es tritt auch auf, wenn ich direkt nach erhalten des istreams versuche, den Uint auszulesen. Es funktioniert ebenfalls nicht, in einen std::string einzulesen. Ich erhalte aber auf die vorausgehende Zeile
if (is.good()) std::cerr << "ALL GOOD\n\n";in meiner Konsole
ALL GOODEDIT: Ich bin grad komplett weg: Wenn ich die Zeile, welche 'rdbuf()' auf den istream ruft, um in in der Konsole auszugeben, auskommentiere, so erhalte ich nicht besagtes Problem.
-
minimales Beispiel
#include <iostream> #include <sstream> int main() { std::istringstream stream("3317454668"); std::cout << stream.rdbuf() << std::endl; int i; stream >> i; if (!stream) std::cout << "failed\n"; return 0; }Kann mir um Himmels Willen bitte jemand erklären, warum rdbuf() das tut, was es tut?
StackOverflow:rdbuf() just returns a pointer to the underlying basic_streambuf object for the given [io]stream object.
Wieso sollte dass die "Position" im Stream ändern?
Edit2: Hab jetzt auch mal hier nachgelesen: http://www.cplusplus.com/reference/ios/ios/rdbuf/
Ich kapier das trotzdem nicht so ganz.
-
Sowas habe ich vermutet, darum immer ein Minimalbeispiel produzieren.
Kann mir um Himmels Willen bitte jemand erklären, warum rdbuf() das tut, was es tut?
rdbuf() macht nichts, aber basic_ostream::operator<< nimmt den Pointer vom basic_streambuf, liest den Inhalt und schreibt ihn raus. Deshalb verändert sich seine Position.
-
OK danke, ich denke ich kann das so halbwegs nachvollziehen. War auf jeden Fall einer der nervigeren Bugs die ich mir eingebaut habe >.>
-
Ich weiss nicht wieso du nicht
weisstwusstest was das Problem ist.
Dafür gibt es Debugger
-
Hey hustbaer,
ich denke, meine Kenntnisse über das Arbeiten mit dem Debugger reichen da vielleicht nicht aus. Alles was ich damit kann ist Breakpoints setzten und schauen, in welcher Zeile es knallt.
Ich denke nicht, dass mir diese Methode da geholfen hätte. Und selbst wenn, ich wäre zu Beginn im Leben nie darauf gekommen, dass es in jener Zeile liegt.
Falls Du mir dazu Näheres erzählen willst, bin ich gewiss voll aufmerksam.
LG
HarteWare
-
Du kannst mit dem Debugger z.B. zeilenweise durch ein Programm durchgehen.
Und du kannst Variablenwerte angucken.
Returnwerte sollte der Debugger normalerweise von sich aus anzeigen.