std::map verliert Einträge



  • // GEKÜRZTE VERSION

    Guten Morgen,

    ich hab hier in der Arbeit ein kleines Problem mit einer std::map.
    Diese verliert nämlich fast ihr Wissen über ihre Einträge.
    Der Post ist ziemlich lang, aber die Technik ist verschachtelt.

    Erst möchte ich euch zeigen was das für eine Map ist:

    // Kann ich leider nicht kürzen...
    namespace kR { 
      // Schlüssel der ersten Map.
      struct baurecht_key {
        string BetrNr;
        string AnwKz;
        string UserName;
    
        baurecht_key(string BetrNr_, string AnwKz_, string UserName_) 
    	: BetrNr(BetrNr_)
    	, AnwKz(AnwKz_)
    	, UserName(UserName_) {}
    
        baurecht_key() 
    	: BetrNr("")
    	, AnwKz("")
    	, UserName("") {}
    
        bool operator==(const baurecht_key& rhs) {
    	if(BetrNr == rhs.BetrNr && AnwKz == rhs.AnwKz && UserName == rhs.UserName)
    	  return true;
    	return false;
       }
    
       struct baurecht_key_cmp {
         bool operator() (const baurecht_key& lhs, const baurecht_key& rhs) {
           if(lhs.BetrNr == rhs.BetrNr
    	     && lhs.AnwKz == rhs.AnwKz
    	     && lhs.UserName == rhs.UserName)
    	   return false;
    	 return true;
         }
       };
    
      enum STATUS{UNBERUEHRT, CHANGED, NEW};
      enum BAURECHT{ALLES, LESEN, SPERRE};
    
      // Wert der zweiten Map
      struct USR_value {
        BAURECHT baurecht;
        long RechtNr;
        STATUS status;
    
        USR_value(BAURECHT baurecht_, long RechtNr_, STATUS status_ = UNBERUEHRT)
    	: baurecht(baurecht_), RechtNr(RechtNr_), status(status_) {}
    
        USR_value() 
    	: baurecht(ALLES), RechtNr(0), status(UNBERUEHRT) {}
    
        bool operator==(const USR_value& rhs) {
          if(baurecht == rhs.baurecht && RechtNr == rhs.RechtNr && status == rhs.status)
    	  return true;
    	return false;
        }
      };
    
      // Diese Map ist Wert in der anderen Map.
      typedef map <long /*ProgIdNr*/, USR_value> UserRechte;
    
      typedef map <baurecht_key, UserRechte, baurecht_key_cmp> AlleUserRechte;
      typedef AlleUserRechte::iterator UserRechteIter;
    }
    

    Diese Map wird in einer Schleife (korrekt) mit den Werten aus der Datenbank gefüllt.
    Greife ich jedoch nach der Schleife einen Wert ab, so bekomme ich nur das mit dem default-Konstruktor erzeuge Objekt geliefert.

    kR::AlleUserRechte allRights;
    kR::baurecht_key key;
    kR::USR_value = value;
    kR::USR_value = val;
    long ProgId = 0;
    int nRet = tblBaurecht.StmtRead();
    
    while(nRet == BRZSQL_NO_ERROR) {
      ProgId = static_cast<long>(tblBaurecht.Col("ProgIdNr"));
      key.BetrNr = 	static_cast<char*>(tblBaurecht.Col("BetrNr"));
      key.AnwKz =  static_cast<char*>(tblBaurecht.Col("AnwKz"));
      key.UserName = static_cast<char*>(tblBaurecht.Col("UserName"));
    
      value.baurecht = static_cast<kR::BAURECHT>(atol(static_cast<char*>(tblBaurecht.Col("RechteSperre"))));
      value.RechtNr = static_cast<long>(tblBaurecht.Col("RechtNr"));
    
      allRights[key][ProgId] = value;
      if(key == kR::baurecht_key("999999", "EK", "BRZ") && ProgId = 1)
        val = allRights[key][ProgId];
    
      nRet = tblBaurecht.GetNext();
    }
    kR::USR_value vil = allRights[kR::baurecht_key("999999", "EK", "BRZ")][1];
    if(val == vil) // UND DIE BEIDEN SIND [b]NICHT[b] GLEICH!
      int i = 0;
    

    Gebe ich die Daten aber aus, dann sind die eingefügten Inhalte exakt vorhanden.
    Auch der oben gesuchte Eintrag!

    CStdioFile mon("C:\\temp\\NachWhile.txt", CFile::modeWrite| CFile::modeCreate);
    CString outt;
      for(kR::UserRechteIter zimbel = allRights.begin(); zimbel != allRights.end(); ++zimbel) {
        for(kR::RechteIter inner = zimbel->second.begin(); inner != zimbel->second.end(); ++inner) {
          outt.Format("[%s, %s, %s][%d] = %d, %d, %d\n", zimbel->first.BetrNr.c_str()
                                  , zimbel->first.AnwKz.c_str()
                                  , zimbel->first.UserName.c_str()
                                  , inner->first
                                  , inner->second.RechtNr
                                  , inner->second.baurecht
                                  , inner->second.status);
    	mon.WriteString(outt);
        }
      }	
    mon.Close();
    

    Warum? Woran liegt das?



  • Kannste das nicht ein bisschen weiter runterkürzen? 😡 😡



  • Ok, den Teil mit der Rekursion hab ich rausgenommen.
    Ich denke der Fehler dort ist nur ein Nachwirken des jetzt vorhandenen Problemes.

    Die Definitionen im namespace kR kann ich aber nicht kürzen - sonst weiß ja keiner mehr was was ist. 🙂



  • hehej schrieb:

    Diese verliert nämlich fast ihr Wissen über ihre Einträge.

    Lass mich raten: Fast heist du hast nur eine einzigen Eintrag in deiner Map.
    Kurt



  • ZuK schrieb:

    hehej schrieb:

    Diese verliert nämlich fast ihr Wissen über ihre Einträge.

    Lass mich raten: Fast heist du hast nur eine einzigen Eintrag in deiner Map.
    Kurt

    Nein, lasse ich die Map nach der Schleife durch die Iteratoren ausgeben, dann hat die Datei genau so viele Zeilen wie ich Datensätze in der Tabelle habe.
    Die Daten sind schon drin...



  • Mir fällt grad auf, dass deine Komparatorfunktion baurecht_key_cmp keine Ordnungsrelation (strict weak ordering) erzeugt. Die Vergleichsfunktion sollte ein "kleiner-als" Operator sein.
    Ich hab mir zwar nicht alles durchgelesen, aber sowas könnte schon dazu führen, dass die map nicht ganz das tut, was man erwartet.



  • hehejo schrieb:

    Nein, lasse ich die Map nach der Schleife durch die Iteratoren ausgeben, dann hat die Datei genau so viele Zeilen wie ich Datensätze in der Tabelle habe.
    Die Daten sind schon drin...

    Was geht denn dann verloren ?

    Bashar schrieb:

    Mir fällt grad auf, dass deine Komparatorfunktion baurecht_key_cmp keine Ordnungsrelation (strict weak ordering) erzeugt. Die Vergleichsfunktion sollte ein "kleiner-als" Operator sein.
    Ich hab mir zwar nicht alles durchgelesen, aber sowas könnte schon dazu führen, dass die map nicht ganz das tut, was man erwartet.

    So änlich war auch meine Vermutung.
    Kurt



  • Bashar schrieb:

    Mir fällt grad auf, dass deine Komparatorfunktion baurecht_key_cmp keine Ordnungsrelation (strict weak ordering) erzeugt. Die Vergleichsfunktion sollte ein "kleiner-als" Operator sein.
    Ich hab mir zwar nicht alles durchgelesen, aber sowas könnte schon dazu führen, dass die map nicht ganz das tut, was man erwartet.

    Ok, das wusste ich nicht, ich hab das so woanders gesehen.
    Mal sehen wie ich das ummünzen kann. So richtig:

    struct baurecht_key_cmp {
      operator <(const baurecht_key & lhs, const baurecht_key & lhs) {
        if(lhs.BetrNr < rhs.BetrNr && lhs.AnwKz < rhs.AnwKz && lhs.UserName < rhs.UserName)
          return true;
        return false;
      }
    };
    

    ZuK schrieb:

    Was geht denn dann verloren ?

    Z.B. wird der Eintrag [999999 EK BRZ][1] nicht mehr gefunden, obwohl ich ihn in der Schleife hinzufüge.
    In meiner (inzwischen entfernten Rekursion) suche ich nach jedem Eintrag und füge den dann hinzu falls es ihn nicht gibt.
    Lasse ich mir nach der Rekursion die Map ausgeben, dann wird's schauerlich:
    Es gibt jeden Key zweimal: Alle alten Werte und alle neu hinzugefügten Werte.

    Also ist wohl baurecht_key_cmp das Böse?!



  • hehejo schrieb:

    Also ist wohl baurecht_key_cmp das Böse?!

    Das dürfte dein fehler sein. Aber deine neu funktion baurecht_key_cmp ist sicher auch nicht viel besser denn du gibst nur dann < zurück wenn alle felder < sind.
    Ich würde mir einen einfacheren Key für die Map einfallen lassen.
    K.



  • hehejo schrieb:

    Mal sehen wie ich das ummünzen kann. So richtig:

    struct baurecht_key_cmp {
      operator <(const baurecht_key & lhs, const baurecht_key & lhs) {
        if(lhs.BetrNr < rhs.BetrNr && lhs.AnwKz < rhs.AnwKz && lhs.UserName < rhs.UserName)
          return true;
        return false;
      }
    };
    

    Nein, erstens, warum operator<? operator() war schon ganz gut. Das dürfte der Compiler gar nicht durchgehen lassen.
    Zweitens funktioniert das so nicht im Sinne einer Ordnungsrelation. Wenn a<b == false ist und b>a==false ist, dann gelten die Elemente als gleich. Das passiert bei dir schon, wenn eine der drei Bedingungen falsch ist, nicht erst, wenn alle drei Elemente gleich sind.

    Du solltest so vorgehen: Zuerst ein Element prüfen, wenn < oder >, sofort true bzw. false zurückgeben, bei Gleichheit das nächste Element in der gleichen Weise prüfen. So wie man auch zwei Strings vergleicht.



  • Du solltest dir evtl. mal anschauen, welcher Art baurecht_key_cmp sein sollte.
    Z.B. ist der default-comparator bei Maps less<key>.
    Es gibt (ich glaube in <algorithm>) ein Funktionsobjekts-Template

    template <class T>
    struct less : public binary_function<T,T,bool>
      bool operator()(const T& x, const T& y) const;
    

    Dieses Funktinsobjekt beruht auf der existenz eines operator< für die KLasse T

    Du kannst also entweder einen operator< für baurecht_key definieren und bei der map Comp auf default lassen, oder du definierst ein Funktionsobjekt(also eines dass den operator() definiert), das eine Ordnungsrelation definiert. Das gute Stück sollte dann von binary_function<baurecht_key, baurecht_key, bool> abgeleitet sein:

    struct baurecht_key_comp 
      : public binary_function<baurecht_key, baurecht_key, bool>
      bool operator()(const baurecht_key& x, const baurecht_key& y) const
        {
        //eine ordentliche Implementation, die auch Gleichheit
        //der einzelnen Komponenten berücksichtigt
        };
    


  • struct baurecht_key {
      string BetrNr;
      string AnwKz;
      string UserName;
      bool operator <(const baurecht_key& rhs) {
        if(BetrNr < rhs.BetrNr)
          return true;
        else if(AnwKz < rhs.AnwKz)
        // oder so: else if(BetrNr >= rhs.BetrNr && AnwKz < rhs.AnwKz)
          return true;
        else if(UserName < rhs.UserName)
          return true;
    
        return false;
      }
    };
    

    Ist der diesmal richtig? Wenn nein, dann verbessert mich bitte!

    Warum sollte man den ableiten? Das hab ich gar nicht verstanden.
    Ich dachte structs kann man nicht erben lassen?!

    binary_function<baurecht_key, baurecht_key, bool>
    


  • hehejo schrieb:

    Ist der diesmal richtig?

    Nein, das ist wieder Käse.
    Üblicherweise macht man das so:

    bool operator <(const baurecht_key& rhs) {
        if(BetrNr != rhs.BetrNr)    return BetrNr < rhs.BetrNr;
        if(AnwKz != rhs.AnwKz)      return AnwKz < rhs.AnwKz;
        return UserName < rhs.UserName;
      }
    


  • Danke! Das muss ich mir noch ein bisschen durch den Kopf gehen lassen.
    Vielen Dank.. das hat mir sehr geholfen! 🙂 🙂


Anmelden zum Antworten