C++ Standard: Unexpected const_iterator in multiset

杀马特。学长 韩版系。学妹 提交于 2019-12-19 06:27:08

问题


I recently ran into an odd issue where I'd get a const_iterator instead of the expected iterator when iterating through a multiset. It turned out to be a non-issue for MSVC but g++ gave me an error:

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

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

Quite a bit of research revealed that is a problem with lots of previous discussion. I found these relevant bits:

  • http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14990
  • http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#322
  • http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#103
  • http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#279
  • http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#528

My background knowledge and grasp on the issue is limited and thus I'd like to know whether the standard doesn't define this behavior well enough in which case g++ and MSVC implement the behavior to their liking or whether either g++ or MSVC deviate from a well-defined standard.

Thanks in advance.


回答1:


The iterators for set and multiset were changed from the standard iterator/const iterator pair to just being const iterators. The reason for this change was that they are ordered containers, and changing the element inside of an iterator can actually invalidate this ordering constraint.

The version of GCC you're testing against has made this change, the version of VC that you're using has not. VC10 (and VC9 SP1, I believe) always return const_iterators from sets and multisets.

23.2.4/6 of the latest draft of C++1x (n3000.pdf at the moment) says

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

std::set and std::multi_set are the associative containers where the value type is the same as the key type.




回答2:


How to fool the compiler for std::set::iterator?

I have struct

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

I want change only member b (b is irrelevant for sorting in set, only member a is compared).

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

Of course more C + + correctly

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


来源:https://stackoverflow.com/questions/2038453/c-standard-unexpected-const-iterator-in-multiset

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!