Mal wieder String nach Zahl (FAQ)



  • Um das FAQ-Topic (http://c-plusplus.net/forum/viewtopic-var-t-is-39488.html) mal etwas zu vertiefen:

    b) String nach Zahl

    Ist die generelle Verwendung der Umwandlung in der folgenden Art eigentlich "teuer"?

    #include <string>
    #include <sstream>
    using namespace std;
    int main()
    {  
    	string s("123");
    	int a;
    
    	istringstream(s) >> a;
    }
    

    Welche der im Topic beschriebenen 5 Wege nehmt ihr wirklich in der Praxis?

    Das obige hat die Eigneschaft dass der Wert von a nicht geändert wird wenn die Umwandlung fehlschlägt, also zum Beispiel wenn der String gar keine Zahl darstellt.
    Allgemein kann man oben noch gut ne Fehlerbehandlung einbauen, z.b.:

    if ((istringstream(s) >> a).fail()) a=0;
    

    oder rabiater

    if ((istringstream(s) >> a).fail()) throw exception();
    

    Wer die Zuweisung offensichtlicher sehen will könnte's auch so schreiben, wobei ganz rechts auch der "Default"-Wert schön lesbar ist.

    a = !(istringstream(s) >> a).fail() ? a : 0;
    

    Eure "Best Practices"?


  • Administrator

    Ich verwende boost::lexical_cast . Sehr angenehm zu handhaben und wirft eine Exception bei einem Fehler. Intern baut es auf die C++ Streams auf.

    Die C++ Streams haben einiges an Overhead, aber meistens fällt das nicht ins Gewicht.

    Übrigens zu Exceptions bei Streams:
    http://www.cplusplus.com/reference/iostream/ios/exceptions/

    Grüssli



  • Es gibt noch eine 6. bekannte Möglichkeit:

    std::string myString = "123";
    int myInt = boost::lexical_cast<int>(myString);
    

    Wirft bei Fehlschlag eine Exception und ist für einzelne Umwandlungen relativ kompakt. Benötigt allerdings die Boost-Bibliothek (welche von vielen C++-Programmierern verwendet wird).

    Ohne Boost kannst du dir auch mit wenigen Zeilen Code eine ähnliche Funktion schreiben.



  • Um einen Default-Wert im Fehlerfall zu setzen, bietet sich

    a = default_wert;
    istringstream(str) >> a;
    

    an. Wenn der Default-Wert 0 und der Typ von a bekannt ist, sind atoi, atof etc. durchaus vertretbar, aber innerhalb einer Template geht das natürlich nicht.

    Ansonsten hängt die Wahl des Mittels natürlich vom Use-Case ab - oft parst man beispielsweise aus einem std::istream &, und dann macht es, wenn man einen String als Quelle hat, natürlich wenig Sinn, etwas anderes als std::istringstream zu benutzen.

    Was Performance angeht - der Overhead der C++-Streams war einst recht groß, da ist aber inzwischen bei allen gängigen Compilern viel geschehen. Zudem stellt sich diese besondere Problematik in der Praxis sowieso meistens in Zusammenhängen, in denen Performance nicht von übergeordneter Bedeutung ist, etwa bei Benutzereingaben auf der Konsole oder per GUI. Es kommt höchst selten vor, dass dort mehr als ein paar Zahlen geparst werden müssen, und bei größeren Datenmengen bemüht man im Zweifel eh eine Datei und meistens auch eine spezielle Parser-Bibliothek.



  • scrontch schrieb:

    Ist die generelle Verwendung der Umwandlung in der folgenden Art eigentlich "teuer"?

    Ja. Aber wie Du siehst, stimmen die Vorurteile gegenüber C++-Programmierern.

    scrontch schrieb:

    Eure "Best Practices"?

    Irgendwie brauche ich das gar nicht. Beim Einlesen der Daten benutze ich >> und danach speichere ich Zahlen in Zahlentypen.



  • if (!(istringstream(s) >> a)) { /* Error! */ }
    

Log in to reply