2010-01-10 8 views
7

Recientemente me encontré con un problema extraño en el que obtendría un const_iterator en lugar del iterator esperado al iterar a través de un multiset. Resultó ser un no-problema para MSVC pero g ++ me dio un error:Estándar de C++: const_iterator inesperado en multiset

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

código relevante:

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); 
    } 
} 

un poco de investigación reveló que es un problema con un montón de discusión previa . He encontrado estos bits relevantes:

Mi conocimiento de fondo y la comprensión de la cuestión es limitado y por lo tanto me gustaría gustaría saber si el estándar no define esto comportamiento suficientemente bien en cuyo caso g ++ y MSVC implementan el comportamiento a su gusto o si g ++ o MSVC se desvían de un estándar bien definido.

Gracias de antemano.

+0

cambio de la decl de 'mío' a 'const myPtr y mine'. Por supuesto, 'tick' tendrá que declararse 'void tick (float) const;' y cualquier miembro de datos modificado por tick necesitará ser 'mutable'. – KitsuneYMG

Respuesta

15

Los iteradores para set y multiset se cambiaron del par de iterador/iterador estándar a ser solo iteradores. La razón de este cambio fue que son contenedores ordenados, y cambiar el elemento dentro de un iterador puede invalidar esta restricción de ordenamiento.

La versión de GCC que está probando ha hecho este cambio, la versión de VC que está utilizando no lo ha hecho. VC10 (y VC9 SP1, creo) siempre devuelven const_iterators de conjuntos y multisedes.

23.2.4/6 del último borrador de C++ 1x (n3000.pdf por el momento) dice

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

std :: set y std :: multi_set son los contenedores asociativos donde el valor tipo es el mismo que el tipo de clave.

+0

¡Impresionante! Acabo de probar VC10b2 y de hecho tengo el mismo error.Ahora bien, si solo entendiera qué parte del estándar exactamente definió esto. – Svenstaro

+0

23.2.4/6 del último borrador de C++ 1x dice "Para los contenedores asociativos donde el tipo de valor es el mismo que el tipo de clave, tanto iterator como const_iterator son iteradores constantes". std :: set y std :: multi_set son los contenedores asociativos donde el tipo de valor es el mismo que el tipo de clave. –

1

Cómo engañar al compilador para std :: set :: iterator?

He struct

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

Quiero cambiar único miembro b (b es irrelevante para la clasificación en conjunto, sólo el miembro de una se compara).

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 

supuesto más C + + correctamente

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

quiere información sobre el estándar y no una solución – owagh

+0

O puede usar 'const_cast'. Por cierto, su solución falla si el elemento se copia o se asigna. – immibis