example c++ g++ visual-c++ standards

example - Estándar de C++: const_iterator inesperado en multiset



multiset c++ (2)

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

Tengo estructura

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

Quiero cambiar solo el miembro b (b es irrelevante para ordenar en conjunto, solo se compara el miembro a).

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

Por 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

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

error: inicialización no válida de la referencia del tipo ''myPtr &'' de la expresión del tipo ''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); } }

Una gran cantidad de investigación reveló que es un problema con mucha discusión previa. Encontré estos bits relevantes:

Mi conocimiento de fondo y comprensión sobre el tema es limitado y, por lo tanto, me gustaría saber si el estándar no define este comportamiento lo 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 por adelantado.


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 con la que está probando ha hecho este cambio, la versión de VC que está utilizando no. 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 en este momento) 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.