Zum Inhalt springen
Topos Uranos

Zusammenfassung

Die Eingabe ist die Grenze, über die die Welt in ein Programm gelangt, und die Welt hält sich nicht an Spezifikationen. Diese Lektion lehrt, ohne Vertrauen zu lesen: ganze Zeilen mit std::getline zu lesen und die leere Zeile zu vermeiden, die entsteht, wenn man es mit >> mischt; den Zustand eines Streams abzufragen und mit ihm drei Situationen zu unterscheiden, die die Lektion Eingabe, Ausgabe und Fehler nur vermengt gesehen hat (die ungültige Eingabe, die Zahl, die nicht passt, und das Ende der Daten); sich mit clear und ignore von einem gescheiterten Lesen zu erholen; und, als sicherste Form, jede Angabe als Text zu lesen und mit std::from_chars umzuwandeln, wobei sie nur angenommen wird, wenn die Umwandlung den ganzen Text verbraucht hat. Sie schließt mit einer Funktion readInt samt Vertrag, die der Rest des Kurses wiederverwenden kann.

Lernziele

  1. Ganze Zeilen mit std::getline lesen, erklären, warum ein getline, das auf ein Lesen mit >> folgt, eine leere Zeile liefert, und dies mit std::ws vermeiden.
  2. Den Zustand eines Streams nach einem Lesen mit fail() und eof() abfragen und mit ihm eine ungültige Eingabe, eine Zahl, die nicht in ihren Typ passt, und das Ende der Eingabe unterscheiden.
  3. Eine Leseschleife schreiben, die sich mit clear und ignore von einer ungültigen Eingabe erholt und die endet, wenn die Eingabe zu Ende geht.
  4. Eine als Text gelesene Zahl mit std::from_chars validieren, wobei verlangt wird, dass kein Fehler auftritt und die ganze Zeichenkette verbraucht wird, und die Validierung in Funktionen mit Vertrag kapseln.

Die Grenze, noch einmal

Die Lektion Eingabe, Ausgabe und Fehler hat drei Tatsachen über std::cin >> n festgestellt: Das Lesen hält, ohne es zu verbrauchen, am ersten Zeichen an, das die Zahl nicht fortsetzen kann; gelingt es ihm nicht, auch nur eines zu lesen, gerät der Stream in einen Fehlerzustand, und jedes weitere Lesen tut nichts; und if (std::cin) erlaubt zu erkennen, ob etwas gescheitert ist. Die Lektion Schleifen fügte hinzu, dass die Bedingung while (std::cin >> value) sowohl endet, wenn die Eingabe zu Ende geht, als auch, wenn eine ungültige Eingabe kommt. Nun aber erkennt ein Programm mit diesen Mitteln, dass etwas schiefgegangen ist, weiß aber nicht, was, und kann nichts anderes tun als aufgeben.

Diese Lektion geht von einem Entwurfsprinzip aus, dem der defensiven Programmierung an der Grenze: Jede Angabe, die hereinkommt, wird validiert, bevor sie verwendet wird, und das Programm, das sie validiert, unterscheidet die ungültige Eingabe, die eine Korrektur zulässt (sie erneut anfordern, sie überspringen, sie melden), vom Ende der Daten, das keine zulässt. Wenn dem so ist, braucht es dreierlei: die Angabe so zu lesen, wie sie geschrieben wurde, also eine Zeile; zu wissen, warum ein Lesen gescheitert ist; und dem Stream die Fähigkeit zum Lesen zurückzugeben.