map mit std::string key liefert falsche Ergebnisse



  • Moin,

    ich habe mal wieder ein Prolem und zwar deklariere ich eine map ind einer klasse

    class X
    {
      protected:
          std::map<std::string, uint> data;
    }
    

    welche ich anhand eienr methode füllen lasse

    void Fill()
    {
       ... getting all availible data handles here
       map[name] = handle;
    }
    

    Jetzt versuche ich darauf zuzugreifen und der string, der erzeugt wird, wird einfach nicht richtig verglichen, sodass die map eben glaubt es würde ein neues element angelegt.

    main()
    {
      X x;
      x.Fill();
    
      /*
       * any = 0
       * values = 1
       */
    
      x["values"] = 20; //<- hier wird neues element angelegt
    
      /*
       * any = 0
       * values = 1
       * values = 20
       */
    }
    

    Wie kann ich das verhindern bzw. wie wird "values" eben als values verglichen und nicht als pointer oder wie auch immer?



  • Es gibt std::find, um zu überprüfen, ob ein Eintrag existiert. Grundsätzlich kann eine std::map aber gar keine doppelten Einträge aufnehmen. Der Eintrag muss also unterschiedlich sein.

    Ansonsten bastel mal ein besser nachvollziehbares und bestenfalls sogar kompilierbares Beispiel.



  • Heißt die Map jetzt data, map oder x?
    Woher weißt du, dass ein neuer Eintrag angelegt wird?



  • manni66 schrieb:

    Heißt die Map jetzt data, map oder x?

    spielt das ne rolle? ist fürn beispiel doch unrelevant

    manni66 schrieb:

    Woher weißt du, dass ein neuer Eintrag angelegt wird?

    weil ich im debugmodus im objektinspektor die map aufgemacht und die einträge angeguckt habe und der "values" eintrag war doppelt mit unterschiedlichen werten (2 für original und 0 für den neu angelegten)



  • Pria schrieb:

    der "values" eintrag war doppelt mit unterschiedlichen werten (2 für original und 0 für den neu angelegten)

    hast du einen quantencomputer?



  • Pria schrieb:

    manni66 schrieb:

    Heißt die Map jetzt data, map oder x?

    spielt das ne rolle? ist fürn beispiel doch unrelevant

    Wenn im Beispiel alle 3 Versionen vorkommen bedeutet das, dass du irgendetwas zeigst, aber nicht den Code den du wirklich benutzt.

    Pria schrieb:

    manni66 schrieb:

    Woher weißt du, dass ein neuer Eintrag angelegt wird?

    weil ich im debugmodus im objektinspektor die map aufgemacht und die einträge angeguckt habe und der "values" eintrag war doppelt mit unterschiedlichen werten (2 für original und 0 für den neu angelegten)

    Da du laut deinem Beispiel 20 reinschreibst, wäre 0 sehr überraschend. Aber im echten Code tust du das ja vermutlich auch nicht ...



  • Ich poste hier mit sicherheit nicht alle 2000 zeilen code, dies sind die relevanten zeilen, wie es in etwa aussieht, ohne wichtige zwischenschritte ausgelassen zu haben

    • definition in klasse mit map<string, uint>
    • vorbelegung durch fill mit string name und uint handle;
    • aufrufen in der main-methode durch klasse.liste["values"] = 20;
    • debug-break, listenwert ist doppelt belegt.

    Nicht mehr nicht weniger!



  • Dann poste doch mal bitte ein kompilierbares (Minimal-)Beispiel, das diesen Fehler erzeugt.

    Edit:

    #include <map>
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    void printMap(map<string, int> const& m)
    {
    	for(auto const& p : m)
    		cout << p.first << " -> " << p.second << endl;
    }
    
    int main()
    {
    	map<string, int> m;
    
    	m["Ding"] = 0;
    	m["Dong"] = 1;
    	m["Value"] = 284;
    
    	printMap(m);
    
    	m["Ding"] = 10;
    
    	printMap(m);
    
    	return 0;
    }
    

    Bei mir funktioniert das einwandfrei:

    Ding -> 0
    Dong -> 1
    Value -> 284
    Ding -> 10
    Dong -> 1
    Value -> 284
    

    .



  • Ich poste hier mit sicherheit nicht alle 2000 zeilen code, dies sind die relevanten zeilen, wie es in etwa aussieht, ohne wichtige zwischenschritte ausgelassen zu haben

    Anscheinend nicht, da ein Fehler vorliegt und er so nicht nachvollzogen werden kann. Du musst dein Code auch nicht hier posten, dafuer gibt es bspw. pastebin.com oder ideone.com.



  • @Pria: unterscheiden sich die Einträge evtl. durch Groß-/Kleinschreibung oder Leerzeichen (vorne oder hinten)?



  • Also nochmal, das beispiel entspricht bereits dem minimalbeispiel
    aber gut,

    #include <map>
    #include <string>
    
    struct X
    {
    	std::map<std::string, int> myMap;
    
    	inline void Fill()
    	{
    		int length = 0;
    		std::string result(20,0);
    		glGetActiveUniformName(2,2,20,&length,&result[0]); //<- binden von name an entsprechendes handle (in diesem Fall handle=2)
                    //könnte aber auch jede andere 3t Anbieter Schnittstellenfunktion sein, die einen string erzeugt
    
    		myMap[result] = 2;
    	}
    };
    
    int main()
    {
        X x;
        x.Fill();
    
        //sizeof mymap = 1
        int exmaple_check = x.myMap["texture"];
    
        //size of mymap = 2 with
        /*
        *  [0] ("texture",2)
        *  [1] ("texture",0)
        */
    
        assert(example_check > 0); //<- fail
    }
    

    So, Originalcode wirklich aufs minimalste reduziert, defakto string "texture" in der Fill-Funktion wird als völlig anderer index behandelt als string "texture" in main(), deshalb doppelte indizierung



  • Da hast du doch den Fehler, genau das was Th69 sagte.

    Dein String ist 20 lang, wird in der Funktion geändert, ist aber immer noch 20 lang. Demnach unterscheiden sich eigentlich gleiche Strings immer noch, weil ihre Länge unterschiedlich ist.

    Heißt im Klartext:

    [0] ("texture            ", 2)
    [1] ("texture", 0)
    

    Edit:
    Lösung: Da du ja eh die neue Stringlänge in deiner Fillfunktion bekommst kannst du einfach en result.resize(length) machen



  • Der Inspektor hat mir nichts in der Richtung angezeigt, wie dem auch sei, ein zusätzliches result.resize(length); hat dem jetzt abhilfe getan.

    Danke für die Hilfe!


Log in to reply