8 votes

Norme C++ : const_iterator inattendu dans un multiset

J'ai récemment rencontré un problème étrange : j'obtenais un const_iterator au lieu de la valeur attendue iterator lors de l'itération dans un multi-ensemble. Il s'est avéré que ce n'était pas un problème pour MSVC, mais que g++ m'a donné une erreur :

erreur : initialisation invalide de la référence de type 'myPtr&' à partir d'une expression de type 'const boost::shared_ptr'

Code correspondant :

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

De nombreuses recherches ont révélé qu'il s'agissait d'un problème lié à de nombreuses discussions antérieures. J'ai trouvé ces passages pertinents :

Mes connaissances et ma compréhension de la question sont limitées et j'aimerais donc savoir si la norme ne définit pas suffisamment bien ce comportement, auquel cas g++ et MSVC l'implémentent à leur guise, ou si g++ ou MSVC s'écartent d'une norme bien définie.

Merci d'avance.

16voto

Terry Mahaffey Points 7368

Les itérateurs pour set et multiset sont passés de la paire standard itérateur/const itérateur à des itérateurs const. La raison de ce changement est qu'il s'agit de conteneurs ordonnés, et qu'un changement d'élément à l'intérieur d'un itérateur peut en fait invalider cette contrainte d'ordre.

La version de GCC que vous testez a fait ce changement, la version de VC que vous utilisez ne l'a pas fait. VC10 (et VC9 SP1, je crois) renvoie toujours des const_iterators à partir d'ensembles et de multisets.

23.2.4/6 du dernier projet de C++1x (n3000.pdf pour l'instant) dit

Pour les con est le même les itérateurs et const_iterator sont des itérateurs constants.

std::set et std::multi_set sont des conteneurs associatifs où le type de valeur est le même que le type de clé.

1voto

Comment tromper le compilateur pour std::set::iterator ?

J'ai struct

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

Je veux changer uniquement le membre b (b n'est pas pertinent pour le tri dans l'ensemble, seul le membre a est comparé).

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

Bien sûr, plus de C + + correctement

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X