Die RICHTIGE Art zu konvertieren



  • me_and_cpp schrieb:

    Verwende std::to_string() und std::stoi(). Das ist genau das, was du suchst.
    Weder mehr noch weniger.

    👍



  • Während std::to_string bei mir häufig im Einsatz ist, war interessanterweise stoi noch nie das, was ich gebraucht habe. Ich finde diese Funktion auch reichlich nutzlos. Der angebliche Vorteil gegenüber atoi ist ja Fehlerkontrolle. Nur funktioniert die bei stoi nur "von links". stoi("1dudum") gibt mir zum Beispiel 1 aus, wobei "1dudum" bestimmt keine Zahl ist. Wenn man es also mit Nutzereingaben zu tun hat, kann man diese Funktion genausowenig wie atoi benutzen, weil man eben Fehleingaben nicht zuverlässig erkennen kann. Problematisch ist das z.B., wenn der Benutzer "1.5" oder "1e4" eingibt und somit offensichtlich (für Menschen) was anderes als 1 meint. Mit boost::lexical_cast<int> ist dieses Problem dann z.B. behoben. Und sobald ich solche Benutzereingaben habe, ist die Effizienz dieser Umwandlung auch ziemlich egal.

    Aber im hier vorliegenden Fall ist ja sowieso immer noch unklar, wozu diese Konvertierung überhaupt benötigt wird.



  • TE:
    Ich habe hier eine Dose Ravioli und habe Probleme, sie aufzumachen. Kann mir jemand helfen?

    Forum:
    Was hast du denn bisher versucht?

    TE:
    Also, ich habe hier einen Hammer. Aber jedes Mal, wenn ich damit auf die Dose haue geht sie zwar auf, aber die Tomatensauce spritzt überall herum.

    Forum:
    Argh, nein, wirf den Hammer weg und benutz´ nen Dosenöffner!

    TE:
    Aber ich möchte gern den Hammer benutzen, weil noch nie etwas mit einem Hammer gemacht habe.

    Forum:
    Nein, der Hammer ist dazu nicht geeignet! Nimm nen Dosenöffner!

    TE:
    Alles, klar, mach ich!

    TE:
    So, ich habe jetzt eine Schneide an den Hammer gebastelt, aber irgendwie funktioniert das nicht richtg. Kann mir jemand helfen?

    Forum:
    ...



  • wob schrieb:

    ... stoi("1dudum") gibt mir zum Beispiel 1 aus, wobei "1dudum" bestimmt keine Zahl ist. Wenn man es also mit Nutzereingaben zu tun hat, kann man diese Funktion genausowenig ...

    Wieso? Genau dafür hat die Funktion den zweiten Parameter (idx), der wird dann nämlich auf die Position des ersten 'd' gesetzt.

    Wenn du nach Ausführung von

    std::string s = "1dudum";
    std::size_t idx;
    int n = std::stoi (s, &idx, 10);
    

    idx mit s.size() vergleichst und das stimmt nicht überein, dann weißt du, dass nicht der ganze String umgewandelt werden konnte und wo die Umwandlung abgebrochen wurde.

    Problematisch ist das z.B., wenn der Benutzer "1.5" oder "1e4" eingibt und somit offensichtlich (für Menschen) was anderes als 1 meint.

    Wieso ist das problematisch? Das machst du genau wie oben und brüllst den Benutzer anschließend an "das ist keine Ganzzahl, du Armleuchter!".
    Oder du erwartest Kommazahlen, dann benutzt du stof.



  • Printe schrieb:

    Wieso? Genau dafür hat die Funktion den zweiten Parameter (idx), der wird dann nämlich auf die Position des ersten 'd' gesetzt.

    Ok, da hast du recht und ich vergesse immer wieder, dass es diesem Parameter gibt. Meine Schuld. Nur warum wird dann bei einem Fehler "von links" eine Exception geworfen? Dann sollte man da stillschweigend 0 zurückgeben - du könntest ja von dann ebenfalls diesen 2. Parameter prüfen. Finde ich inkonsistent.

    Es ist außerdem extrem umständlich zu bedienen. Also lohnt es sich, das stoi zu in eine eigene Funktion zu wrappen. Man kann ja auch ein optional<int> zurückgeben oder immer ne Exception werfen. Für welche Fälle soll es denn nützlich sein, rechts von der Zahl Fehleingaben zu ignorieren, was ja der Default ist? Wäre es, wenn der 2. Parameter nicht angegeben wird, nicht viel besser/konsistenter, auch bei Fehlern von rechts eine Exception zu werfen?

    Problematisch ist das z.B., wenn der Benutzer "1.5" oder "1e4" eingibt und somit offensichtlich (für Menschen) was anderes als 1 meint.

    Wieso ist das problematisch? Das machst du genau wie oben und brüllst den Benutzer anschließend an "das ist keine Ganzzahl, du Armleuchter!".

    Genau. Nur dass es zu kompliziert ist. (wie gesagt, irgendwann hatte (ggf. sogar hier?) mich jemand schonmal auf den 2. Parameter hingewiesen - ich vergesse den immer und sehe auch in Code (fast?) immer nur stoi("ein arguemnt") .

    Ich nehme also hiermit meine Kritik an stoi halb zurück 😉



  • wob schrieb:

    Nur warum wird dann bei einem Fehler "von links" eine Exception geworfen? Dann sollte man da stillschweigend 0 zurückgeben - du könntest ja von dann ebenfalls diesen 2. Parameter prüfen. Finde ich inkonsistent.

    Eine "stillschweigende Default-0" ist aber was anderes als eine eindeutig im String erkannte 0. Das muss unterscheidbar sein.

    Es gibt mehrere mögliche Ansätze, z.B.:

    int stoi (string s) throw;    // so wirds gemacht
    int stoi (string s, size_t * idx); // idx ist nicht optional - man wird zu nichts gezwungen, aber doch nachdrücklich erinnert
    bool stoi (string s, int & result); // result nur gültig, wenn rückgabe == true
    

    Die Designer der c++-Lib haben sich für die erste Variante entschieden, vermutlich deshalb, weil damit eine garantiert mögliche Konvertierung am elegantesten zu programmieren ist und alle anderen mit vertretbarem Aufwand in etwas Elegantes gewrappt werden können.



  • An dieser Stelle möchte ich nochmal sagen, dass ich sehr froh über jede Hilfe bin, die ich hier erhalte.

    Ihr habt mich überzeugt. Ich werde mein Projekt mit Strings machen. Die CFramework Klasse ist schon fertig. Jetzt erstmal was schönes essen und dann kommt der Rest. 🙂



  • String wird mit st abgekürzt, oder?

    Z.B. std::string stName;



  • Bizarreofnature schrieb:

    String wird mit st abgekürzt, oder?

    Z.B. std::string stName;

    ne, mit "str"



  • Garnicht. Was soll "Name" sonst sein, als ein String? Welchen mehrwert hat da ein Präfix? Schau mal https://stackoverflow.com/questions/111933/why-shouldnt-i-use-hungarian-notation an. Eventuell auch Making Wrong Code look Wrong.



  • wob schrieb:

    Printe schrieb:

    Wieso? Genau dafür hat die Funktion den zweiten Parameter (idx), der wird dann nämlich auf die Position des ersten 'd' gesetzt.

    Ok, da hast du recht und ich vergesse immer wieder, dass es diesem Parameter gibt. Meine Schuld. Nur warum wird dann bei einem Fehler "von links" eine Exception geworfen? Dann sollte man da stillschweigend 0 zurückgeben - du könntest ja von dann ebenfalls diesen 2. Parameter prüfen. Finde ich inkonsistent.

    Ja, ist inkonsistent. Ich vermute(!), dass die Erfinder der stdlib einen Parser im Hinterkopf hatten. Du übergibst einen Zeiger auf den Punkt, an dem Dein Parser steht und bekommst im 2. Parameter zurück, wo Du weiterparsen musst.



  • Ja, es ist konsistent mit iostreams.

    Es ist auch völlig ok, wenn man sowas machen will. Nur MUSS man, um das zu testen, ein Nicht-nullptr 2. Argument übergeben. Daher denke ich, dass genau dieser Fall, also KEIN 2. Argument angegeben, zu einem sichtbaren Fehler hätte führen sollen. Wenn jemand das 2. Argument ausliest, ist es völlig ok, dann bis dahin zu konvertieren.

    Aber egal, der Standard ist nun einmal wie er ist - und ich benutze eben mein eigenes stoi, das sich eben anders verhält.

    Jedenfalls muss man immer dran denken, dass stoi("42 ein string, sonst kein weiterer parameter") keinen Fehler wirft. Sofern ich das Bewusstsein dafür erhöht habe, bin ich ja auch schon glücklich 🙂



  • Das gesamte Projekt ist jetzt auf String umgestellt.

    Danke nochmal an alle. Es ist wirklich besser als C-Strings.

    Und mehr oder weniger gearbeitet habe ich ja jetzt mit char. Also ist das wohl auch abgehakt.



  • wob schrieb:

    Es ist auch völlig ok, wenn man sowas machen will. Nur MUSS man, um das zu testen, ein Nicht-nullptr 2. Argument übergeben. Daher denke ich, dass genau dieser Fall, also KEIN 2. Argument angegeben, zu einem sichtbaren Fehler hätte führen sollen.

    Warum denn? Das Verhalten ist doch ausführlichstens dokumentiert für jeden, der lesen kann.

    Man kann von einem Programmierer erwarten, dass er eine Funktion, die er erstmals verwendet, mal kurz in der Doku nachliest. Und dass drei Parameter, von denen zwei optional sind, zumindest mal Interesse wecken. Oder dass man sich selbst die Frage stellt "was macht die Funktion eigentlich, wenn sie einen String nicht konvertieren kann?"

    Wem das alles egal ist, wer einfach nur blind Code kopiert, den er im Internet gefunden hat, der muss halt selbst die Erfahrungen machen.



  • Printe schrieb:

    Warum denn? Das Verhalten ist doch ausführlichstens dokumentiert für jeden, der lesen kann.

    Das ist ein nutzloses Totschlagargument.

    Das Verhalten sollte so sein, dass es möglichst nützlich für den gemittelten Benutzer ist und weder Inkonsistenzen noch sonstige Überraschungen bietet.

    Wer schaut schon in die Dokumentation?! (Zumal bei 3rd party libraries gerne mal die Doku völlig veraltet ist!)



  • wob schrieb:

    Das ist ein nutzloses Totschlagargument.

    Von mir aus. Aber es ist wahr.

    Das Verhalten sollte so sein, dass es möglichst nützlich für den gemittelten Benutzer ist ...

    Das kann für spezialisierte Anwenderfunktionen gelten. Für Funktionen in Standardbibliotheken gilt, dass sie ihre Aufgabe möglichst umfassend erfüllen sollen. Den spezialisierten Wrapper kann sich dann jeder Anwender selber bauen, wenn er das für nötig hält.

    Wer schaut schon in die Dokumentation?! (Zumal bei 3rd party libraries gerne mal die Doku völlig veraltet ist!)

    DAS ist ein Totschlagargument. Und die Doku auf cppreference.com ist alles andere als veraltet.



  • Ich muss mich wob mit seiner Kritik an stoi zumindest zum Teil anschließen.
    Wenn ich selber entwickel, werde ich wahrscheinlich in die Doku schauen, da ich Fehler in der Eingabe behandeln muss. Anders sieht es aus, wenn ich Code von anderen lese. Da erwarte ich, dass die Funktionen das machen, was ich vom Namen her erwarte. Vor allem, wenn sie aus der Standard Bibliothek stammen.
    Mal als Beispiel:

    try
    {
       auto result = std::stoi(irgendeinEingabeString);
    }
    catch(...)
    {
       LOG_ERROR("DAU ist zu blöd eine ganze Zahl einzugeben");
    }
    

    Wenn ich das lese, gehe ich davon aus, dass der Entwickler sich gedanken um die Fehlerbehandlung gemacht hat. Das aber nur ein Teil der möglichen Eingabefehler behandelt werden, geht daraus nicht vor. Das ist meiner Meinung nach unschön.



  • Printe schrieb:

    Wer schaut schon in die Dokumentation?! (Zumal bei 3rd party libraries gerne mal die Doku völlig veraltet ist!)

    DAS ist ein Totschlagargument.

    Von mir aus. Aber es ist wahr. 😉


Anmelden zum Antworten