Ist es sicher nicht auf map.end() zu prüfen?



  • Hallo,

    um den Code etwas zu kürzen möchte ich folgendes tun:

    std::map<std::string, std::string> myMap;
    
    bool myVar = (myMap.find("Schlüssel")->second.compare("Wert") == 0)? true:false;
    

    In Test's hat das geklappt, auch wenn der Schlüssel gar nicht existiert. Dennoch frage ich mich, ob man dass so machen kann oder ob es dort zu unvorhersehbaren verhalten kommen kann.

    Spoocy



  • map::find gibt, falls es ein Element nicht findet, einen Iterator auf map::end() zurück und diesen Iterator darf man nicht dereferenzieren. Dein Code hat also undefiniertes Verhalten. Vielleicht ist map::operator[] aber was passendes für dich. Wenn dieser den Schlüssel nicht findet wird ein leeres Element hinzugefügt. Der Code könnte dann so aussehen:

    bool myVar = myMap["Schlüssel"] == "Wert";
    

    Wenn das hinzufügen von leeren Elementen nicht OK ist, musst du bei deinem alten Code vorher testen ob das Element gefunden wurde.


  • Mod

    Warum zum Teufel verwendest du compare ? Und den ternären Operator um aus true true und aus false false zu machen? 😮

    Spontan hätte ich vorgeschlagen, den Iterator von find zu prüfen und entsprechend zu reagieren falls kein solcher Key existiert, aber die passende Funktion (und "Fehler"behandlung) hängt ggf. vom Kontext ab, den du uns verschwiegen hast.



  • Hatte befürchtet das es nur glück ist, dass es bei den Test's keine Fehler gegeben hatte.

    Der Grund für compare ist, bei der map handelt es sich um eine Konfigurations-Map, welche simpel Schlüsse = Wert aus einer Datei speichert. Der Wert kann sowohl ein String sein als eben auch nur "1". Auch will ich mit compare die Möglichkeit nutzen das der Wert das Wort "true" erlaubt. Im weiterem verlauf des Code muss ich dann eben wissen ob der Benutzer den Schlüssel mit "true" belegt hat. Da ich das noch mehrfach Prüfe, dachte ich mir, es ist besser ein mal mit compare zu arbeiten und dann wirklich den echten bool type zu haben, als an mehreren stellen compare zu nutzen.


  • Mod

    MrSpoocy schrieb:

    Hatte befürchtet das es nur glück ist, dass es bei den Test's keine Fehler gegeben hatte.

    Der Grund für compare ist, bei der map handelt es sich um eine Konfigurations-Map, welche simpel Schlüsse = Wert aus einer Datei speichert. Der Wert kann sowohl ein String sein als eben auch nur "1". Auch will ich mit compare die Möglichkeit nutzen das der Wert das Wort "true" erlaubt. Im weiterem verlauf des Code muss ich dann eben wissen ob der Benutzer den Schlüssel mit "true" belegt hat. Da ich das noch mehrfach Prüfe, dachte ich mir, es ist besser ein mal mit compare zu arbeiten und dann wirklich den echten bool type zu haben, als an mehreren stellen compare zu nutzen.

    Du hast merkwürdige Vorstellungen über Datentypen.



  • Du vergleichst Strings also kriegst du auch einen String Vergleich. Ein String mit dem Inhalt "1" oder "true" ist immer noch ein String und wird nicht besonders behandelt. Wir sind hier nicht bei PHP.



  • Mir ist doch vollkommen bewusst das ich einen String vergleich mache. Das oben ist doch nichts anderes als

    auto it = myMap.find("Schlüssel");
    bool myVar = false;
    
    // Meine Fragestellung
    // if (it != myMap.end() {
    	if (it->second.compare("1") == 0)
    	{
    		myVar = true;
    	}
    //}
    

    Und genau das soll es ja auch sein. Entweder wir reden an einander vorbei oder ich weis echt nicht was jetzt so falsch daran ist (mal abgesehen davon das ich vorher nicht auf .end() prüfe. Was aber genau meine Fragestellung war.



  • Die Antworten sind klar und deutlich und beziehen sich auf Deinen Code.

    Also erst ist die Antwort zu Deiner Frage wie bereits erwähnt "nein". Es ist nicht sicher, bzw. falsch, nicht auf map.end() zu prüfen.

    Der Hinweis auf den ternären Operator ?: bezieht sich auf ein Konstrukt, was Du verwendest:

    bool myVar = irgendeineBedingung ? true : false
    

    Das ist absolut identisch mit

    bool myVar = irgendeineBedingung;
    

    Der ternäre Operator ist einfach nur überflüssig.

    Der nächste Hinweis bezieht sich auf compare:

    irgendeinStdString.compare("blah")==0
    

    ist wieder identisch mit:

    irgendeinStdString == "blah"
    

    Es gibt keinen Grund hier compare zu verwenden. Es verringert lediglich die Verständlichkeit des Codes.

    So, wie ich verstanden habe, suchst Du in einer map einen Wert, welcher ein std::string ist. Und Du möchtest wissen, ob dieser Wert "1" oder "true" enthält. Dann mache genau das.

    auto it = myMap.find("Schlüssel");
    bool myVar = it != myMap.end()
      && (it->second == "true"
       || it->second == "1")
    

    Damit hast Du kurz und knapp und vor allem sicher sowohl den Iterator abgefragt als auch die Liste einen der gewünschten Werte enthält.

    Wobei ich mich schon frage, warum man bool Werte als Strings ablegen muss. Aber das wirst Du wissen und eigentlich ist mir das egal.


  • Mod

    Das komische ist halt, dass du wohl die einzige Person auf der Welt bist, die string::compare benutzt, anstatt ==. Dazu noch diese komischen Spielchen mit true und false. Einfach so:

    bool myVar = (it->second.compare == "1");   // Klammern sind zwar eigentlich nicht nötig, aber besser lesbar.
    

    Mir ist doch vollkommen bewusst das ich einen String vergleich mache.

    Deine Begründung im vorherigen Beitrag klang aber ganz anders.

    Der Wert kann sowohl ein String sein als eben auch nur "1". Auch will ich mit compare die Möglichkeit nutzen das der Wert das Wort "true" erlaubt

    😕
    edit: Aha 💡 ! Dank tntnets Interpretation verstehe ich jetzt, was gemeint war.



  • Danke für die Anregungen!

    Aus welchem Grund auch immer, wusste ich nicht das es auch simpel mit string == "" geht. Bestimmt hatte ich es mal versucht, irgend was vergessen und dann das empfinden das dieses nicht geht.

    Warum ich einen bool als String speichern möchte/muss ist, die map spiegelt eine simple Konfigurationsdatei da, welche eben als wert auch string zu lässt z.B path = c:\... Ich könnte zwar 2 maps machen, aber dann muss ich ggf. auch immer beide nach dem Schlüssel durchsuchen.

    Ich bin immer offen für Ideen und Verbesserungen! Aber ich muss auch sagen, das der Ton teilweise echt "rau" wird, nur weil ich etwas nicht so mache wie es vielleicht jemand anders macht. Die Hilfe hier im Forum ist echt groß und ich bin auch sehr dankbar dafür!

    Edit: Ich hätte da gleich noch nee frage bezüglich "überflüssig"

    // tstring = std::wstring oder std::string
    
    void function(const tstring &key)
    {
    
    }
    
    // #1
    function(_T("schlüssel"));
    // #2
    function(tstring(_T("schlüssel"));
    

    Macht 1 oder 2 einen Unterschied oder optimiert der Compiler das eh weg/dazu?



  • MrSpoocy schrieb:

    Macht 1 oder 2 einen Unterschied oder optimiert der Compiler das eh weg/dazu?

    Ist identisch. Es wird immer der Konstruktor von tstring aufgerufen. Ich würde daher das tstring(...) einfach weglassen.


Log in to reply