2010-01-10 6 views
7

Ich lief vor kurzem in einem seltsamen Problem, wo ich eine const_iterator statt der erwarteten iterator beim Iterieren durch ein Multiset bekommen würde. Es stellte sich heraus, ein Nicht-Thema für MSVC sein, aber g ++ mir ein Fehler gab:C++ Standard: Unerwarteter const_iterator in Multiset

error: invalid initialization of reference of type 'myPtr&' from expression of type 'const boost::shared_ptr'

Relevante Code:

typedef std::multiset<myPtr> myList; 
myList _mystuff; 
void tick(float dt) 
{ 
    for (myList::iterator i = _mystuff.begin(); i != _mystuff.end(); ++i) 
    { 
     myPtr &mine = *i; // g++ problem here, not for MSVC 
     // const myPtr &mine = *i; works fine for g++ 
     mine->tick(dt); 
    } 
} 

Ganz ein wenig Forschung ergab, dass ein Problem mit vielen vorherigen Diskussion . Ich fand diese relevanten Bits:

Mein Wissen Hintergrund und greifen auf die Frage beschränkt ist und so würde ich möchte wissen, ob der Standard dies nicht definiert Verhalten gut genug, in diesem Fall implementieren g ++ und MSVC das Verhalten nach ihren Wünschen oder ob entweder g ++ oder MSVC von einem wohldefinierten Standard abweichen.

Vielen Dank im Voraus.

+0

Änderung der Decl von 'mine' zu 'const myPtr & mine'. Natürlich muss "tick" als "void tick (float) const;" deklariert werden und jedes durch tick modifizierte Datenelement muss "veränderbar" sein. – KitsuneYMG

Antwort

15

Die Iteratoren für Set und Multiset wurden vom Standard-Iterator/Const-Iterator-Paar in Const-Iteratoren geändert. Der Grund für diese Änderung war, dass es sich um geordnete Container handelt, und das Ändern des Elements innerhalb eines Iterators kann diese Ordnungsbeschränkung tatsächlich ungültig machen.

Die Version von GCC, gegen die Sie testen, hat diese Änderung vorgenommen, die Version von VC, die Sie verwenden, nicht. VC10 (und VC9 SP1, glaube ich) geben const_iterators immer aus Sätzen und Multisets zurück.

23.2.4/6 des neuesten Entwurf von C++ 1x (n3000.pdf im Moment) sagt

For associative containers where the value type is the same as the key type, both iterator and const_iterator are constant iterators.

std :: set und std :: multi_set sind die assoziativen Container, in denen der Wert Typ ist identisch mit dem Schlüsseltyp.

+0

Super! Ich habe gerade VC10b2 getestet und tatsächlich habe ich den gleichen Fehler bekommen.Jetzt, wenn ich nur verstanden habe, welcher Teil des Standards genau dies definiert. – Svenstaro

+0

23.2.4/6 des letzten Entwurfs von C++ 1x sagt "Bei assoziativen Containern, bei denen der Werttyp dem Schlüsseltyp entspricht, sind sowohl Iterator als auch Const_iterator konstante Iteratoren." std :: set und std :: multi_set sind die assoziativen Container, in denen der Werttyp dem Schlüsseltyp entspricht. –

1

Wie den Compiler für std :: set :: iterator täuschen?

I struct habe

struct _item { 
    int a; 
    int b; 
    bool operator <(const _item& x) const {return a<x.a;} 
}; 

I geändert werden sollen einziges Mitglied b (b ist nicht relevant für die in Satz sortiert wird, wird nur ein Mitglied verglichen).

std::set<_item> data; 
std::set<_item>::iterator iter=data.begin(); 
iter->b=0; // error !!! 

Avada Kedavra!

struct _item { 
    int a; 
    int b; 
    _item* self; 
    _item() {self=this;} 
    bool operator <(const _item& x) const {return a<x.a;} 
}; 
iter->self->b=0; // Success !! Tested on VC10 

Natürlich mehr C + + richtig

struct _item { 
    int a; 
    int b; 
private: 
    _item* self; 
public: 
    _item() {self=this;} 
    bool operator <(const _item& x) const {return a<x.a;} 
    int& bReference() const {return self->b;} 
}; 
std::set<_item> items; 
std::set<_item>::iterator iter=items.begin(); 
iter->bReference()=0; // Success !! Tested on VC1 
+1

er möchte Informationen über den Standard und keine Problemumgehung – owagh

+0

Oder Sie könnten 'const_cast' verwenden. Ihre Lösung schlägt übrigens fehl, wenn das Element kopiert oder zugewiesen wird. – immibis