none
Problem mit std::map<const ...., ....> RRS feed

  • Frage

  • Hallo!

    Ich sitze gerade vor einem Problem:

    struct ltUnitType { bool operator()(const IUnit* u1, const IUnit*u2) const { return strcmp(u1->getUnitType(), u2->getUnitType()) < 0; } };

    typedef std::map<const RankedCombat::IUnit*, unsigned, ltUnitType> count_map_t; count_map_t count_map; for(auto unit:units) { count_map_t::iterator i = count_map.find(unit); (*i).second; // <- schon DAS schmeisst einen Error if(i == count_map.end()) { count_map[unit] = 1; } else { ++count_map[unit]; } }

    1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\utility(114): error C2166: L-Wert gibt ein const-Objekt an
    1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\utility(113): Bei der Kompilierung der  Klassen-template der std::pair<_Ty1,_Ty2> &std::pair<_Ty1,_Ty2>::operator =(const std::pair<_Ty1,_Ty2> &)-Memberfunktion
    1>          with
    1>          [
    1>              _Ty1=const RankedCombat::IUnit *const ,
    1>              _Ty2=unsigned int
    1>          ]
    1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility(2646): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::pair<_Ty1,_Ty2> &std::pair<_Ty1,_Ty2>::operator =(const std::pair<_Ty1,_Ty2> &)".
    1>          with
    1>          [
    1>              _Ty1=const RankedCombat::IUnit *const ,
    1>              _Ty2=unsigned int
    1>          ]
    1>          c:\data\projects\darkorb\libgexpgui\systemfleet.cpp(71): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "std::pair<_Ty1,_Ty2>".
    1>          with
    1>          [
    1>              _Ty1=const RankedCombat::IUnit *const ,
    1>              _Ty2=unsigned int
    1>          ]


    Ich kann nur mit den Achseln zucken. Jedenfalls mal nachgeschlagen: Da scheinen die Fehlermeldungen zu spinnen oder der Kompiler den Geist aufzugeben. Auf den zitierten Block folgt noch etwas - wenn man das auskommentiert kompiliert der Block problemlos. Schon beim ersten Durchblättern der Fehler wird's komisch. Da:

    template<class _FwdIt,
    	class _Ty> inline
    	void _Fill(_FwdIt _First, _FwdIt _Last, const _Ty& _Val)
    	{	// copy _Val through [_First, _Last)
    	for (; _First != _Last; ++_First)
    		*_First = _Val;
    	}
    

    werde ich hingeschickt. Sollte durch die Zeile nie und nimmer aufgerufen werden, denke ich.

    Mfg

    Heiko

    Montag, 14. Juli 2014 18:16

Alle Antworten

  • Wenn ich Deinen Code mit einer Testklasse verwende kompiliert der Code ohne Probleme.

    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de

    Dienstag, 15. Juli 2014 09:34
    Moderator
  • Hi, Martin!

    Ich sag ja: das scheint am Kontext zu liegen. Ist mir echt schleierhaft. Kann das Problem beliebig reproduzieren in dem Projekt. Weiter ginge es mit

    struct ltExpForKill {
    	bool operator()(const count_map_t::value_type& u1, const count_map_t::value_type& u2) const {
    		return u1.first->getExperienceForKill() < u2.first->getExperienceForKill();
    			}
    		};
    
    typedef std::vector<count_map_t::value_type> sorted_t;
    sorted_t sortedUnits;
    sortedUnits.reserve(count_map.size());
    		
    for(count_map_t::iterator i = count_map.begin(); i != count_map.end(); ++i) {
    	auto k = std::lower_bound(sortedUnits.begin(), sortedUnits.end(), *i, ltExpForKill());
    	sortedUnits.insert(k, *i);
    }
    
    Wenn ich den Block auskommentiere, funktioniert es. Wenn ich ihn drin lasse schmeisst es den Fehler im oberen Block.
    Dienstag, 15. Juli 2014 09:39
  • Im ganzen nochmal

    typedef std::map<const RankedCombat::IUnit*, unsigned, SortingPredicates::ltUnitType> count_map_t;
    count_map_t count_map;		
    		
    for(auto unit:units) {			
    	count_map_t::iterator i = count_map.find(unit);
    	if(i == count_map.end()) {				
    		count_map[unit] = 1;
    	} else {
    		++i->second;  /************** Error(see below) ***************/
    	}
    }
    		
    struct ltExpForKill {
    	bool operator()(const count_map_t::value_type& u1, const count_map_t::value_type& u2) const {
    		return u1.first->getExperienceForKill() < u2.first->getExperienceForKill();
    	}
    };
    
    /***************** If using this block to sort the units the error is generated
    typedef std::vector<count_map_t::value_type> sorted_t;
    sorted_t sortedUnits;
    sortedUnits.reserve(count_map.size());
    		
    for(count_map_t::iterator i = count_map.begin(); i != count_map.end(); ++i) {
    	auto k = std::lower_bound(sortedUnits.begin(), sortedUnits.end(), *i, ltExpForKill());
    	sortedUnits.insert(k, *i);
    }
    /*******************************************/
    
    /********** Using this works ******/
    typedef std::multiset<count_map_t::value_type, ltExpForKill> sorted_t;
    sorted_t sortedUnits;
    sortedUnits.insert(count_map.begin(), count_map.end());
    /*********************************/
    
    for(sorted_t::iterator i = sortedUnits.begin(); i != sortedUnits.end(); ++i) {
    	auto unit = (*i).first;
    	const unsigned count = i->second;
    	SystemFleetUnitPanel *panel = new SystemFleetUnitPanel(i->first, m_FleetUnits, i->second);
    	m_UnitPanels.push_back(panel);
    	if(i->second <= 1) {
    		panel->setSliderColor(m_UnitsColor);
    	}
    }

    Dienstag, 15. Juli 2014 10:02
  • Hallo,

    Ihr Problem ist, dass value_type aus der Map, den Schlüsselwert konstant setzt. Das ergibt auch Sinn, denn die Werte der Schlüssel sollen nicht geändert werden, nachdem sie in die Map eingetragen wurden. Das heißt für Sie, dass Sie alle count_map_t::value_type durch std::pair<const IUnit*, unsigned> ersetzen müssen.

    Viele Grüße

    App-Entwickler-Hotline für MSDN Online Deutschland

    Disclaimer:
    Bitte haben Sie Verständnis dafür, dass wir hier auf Rückfragen gar nicht oder nur sehr zeitverzögert antworten können.
    Bitte nutzen Sie für Rückfragen oder neue Fragen den telefonischen Weg über die App-Entwickler-Hotline: http://www.msdn-online.de/Hotline

    Es gelten für die App-Entwickler-Hotline und dieses Posting diese Nutzungsbedingungen , Hinweise zu Markenzeichen, Informationen zur Datensicherheitsowie die gesonderten Nutzungsbedingungen für die App-Entwickler-Hotline.

    Dienstag, 15. Juli 2014 10:21
  • Das ist eigentlich kein Problem. Die Funktionen von IUnit, die benutzt werden, sind alle const. Sonst würde ja auch der 2. Block nicht kompilieren. Da muss irgendetwas anderes falsch sein.

    Die Zeile, an welcher der Fehler gemeldet wird, sollte nie und nimmer irgendeine Container-Funktion aufrufen. Aber dahin verweist die Fehlerausgabe. _Fill(....) wird glaube ich benutzt, um einen Container mit einem bestimmten Wert zu initialisieren.

    __

    PS: Entschuldigung. Ich beginne gerade zu verstehen. Der Typ des 1. Paar-Feldes ist "const IUnit* const" aufgrund des konstanten Schlüsselwertes. Das ändert hier aber trotzdem nichts, weil das Feld nirgendwo verändert wird, es sei denn vector<>::insert benutzt den =-Operator. Ob das so ist und sein muss, müsste ich noch nachschlagen. Der gemeldete Fehler jedenfalls macht trotzdem keinen Sinn.

    Dienstag, 15. Juli 2014 10:27
  • Hallo,
    count_map_t::value_type ist vom Typ std::pair<IUnit const* const, unsigned int>. Das bedeutet, dass first ein konstanter Zeiger auf ein konstantes Objekt ist. Sie können also weder das Objekt auf das der Zeiger zeigt ändern, noch den Zeiger im Pair selber! Nun muss std::vector::insert aber unter Umständen seine Elemente verschieben, kann das aber nicht, weil first aus dem Pair nicht überschrieben werden darf (weil es const ist).

    Viele Grüße

    App-Entwickler-Hotline für MSDN Online Deutschland

    Disclaimer:
    Bitte haben Sie Verständnis dafür, dass wir hier auf Rückfragen gar nicht oder nur sehr zeitverzögert antworten können.
    Bitte nutzen Sie für Rückfragen oder neue Fragen den telefonischen Weg über die App-Entwickler-Hotline: http://www.msdn-online.de/Hotline

    Es gelten für die App-Entwickler-Hotline und dieses Posting diese Nutzungsbedingungen , Hinweise zu Markenzeichen, Informationen zur Datensicherheitsowie die gesonderten Nutzungsbedingungen für die App-Entwickler-Hotline.

    Dienstag, 15. Juli 2014 10:39
  • Hallo, ja da habe ich auch gerade dran gedacht, während Sie geschrieben haben. Ich kenne die genaue Semantik des vector::insert jetzt nicht aus dem Kopf, muss ich gestehen. Werfen Sie einen Blick auf mein Edit oben.
    Dienstag, 15. Juli 2014 10:47
  • Also ich hab mal kurz ein Proposal für die move-semantics überflogen und einen kleinen Test gemacht.

    struct tst_t {
    	const int a;
    	tst_t() : a(1) {}
    };
    std::vector<const tst_t> tst;
    tst.push_back(tst_t());
    tst.insert(tst.begin(), tst_t());

    generiert einen Fehler aufgrund der move-semantics. Dabei ist der vector explizit aus "const tst_t" zusammengesetzt. Für das insert sollte, denke ich, in dem Fall sowieso der Kopienkonstruktor verwendet werden.

    Ich bin mir fast sicher, dass das mit einer STL von vor 3 Jahren Problemlos kompiliert hätte, kann das aber leider nicht nachprüfen.

    Dienstag, 15. Juli 2014 11:23
  • Eine Frage noch aus Interesse nach Lesen des C++ 11-Standards: das pair ist mit einem konstanten Member ja so offenbar nicht mehr MoveAssignable. Wird das noch geändert werden?
    Mittwoch, 16. Juli 2014 18:53