VS2010 中Set容器的 iterator 被默认定义为了const_iterator,导致通过iterator复制的操作失败

VS2008 到 VS2010 STL关联容器set 的一点变化

最近在把项目从vs2008移植vs2010的时候, 发现在vs2008下编译通过的代码却在vs2010编译时出现错误。下面是代码的一个简化的示例:

vector<int> v(10, 1);

set<int> s(v.begin(), v.end());

   

set<int>::iterator i = s.begin();

(*i) = 0; // 这行赋值导致VS2010编译失败

 

这段代码在VS2008中顺利通过编译,但在VS2010中出现以下错误:

error C3892: 'i' : you cannot assign to a variable that is const

 

这说明编译器认为i是一个const变量, 可我们明明定义i为set<int>::iterator而不是set<int>::const_iterator, 是哪里出了问题?难道VS2010做了一些特殊处理?可这种特殊处理为什么要导致不能向后兼容呢?要想弄清楚怎么回事, 最直接的方法就是看看VS2010中set的源代码,其中有这么一段:

 

typedef _Tree_const_iterator<_Mybase> const_iterator;

 

typedef typename _STD tr1::conditional<

_STD tr1::is_same<key_type, value_type>::value, const_iterator,

_Tree_iterator<_Mybase> >::type iterator;

 

上面的代码说明const_iterator依然具有const属性,但对于iterator的定义要依赖于key_type和value_type是否是同一种类型,而关联容器set就正是key和value是同一种类型的容器,所以上面的定义相当于:

typedef const_iterator iterator;

所以对于set来说iterator和const_iterator都具有const属性,不能修改set容器中的值。这就解释了为什么一开始的复值语句为什么会失败。

 

接下来的问题是为什么VS2010要做这样不向后兼容的改变?为了更加安全?我查阅了C++ 98 和C++ 2003的标准, 其中关于关联容器iterator的描述并没有明确指出set的iterator必须是const的。之后在C++标准定义网站上在标准库的defect report中找到了答案, defect 103 描述了为什么要将set的iterator改为const的。下面是摘录的一部分:

103. set::iterator is required to be modifiable, but this allows modification of keys

Section: 23.2.4 [associative.reqmts] Status: CD1 Submitter: AFNOR Opened: 1998-10-07 Last modified: 2008-09-26

Proposed resolution:

At the end of paragraph 5: "Keys in an associative container are immutable."

At the end of paragraph 6: "For associative containers where the value type is the same as the key type, both iterator and const_iterator are constant iterators. It is unspecified whether or not iterator and const_iterator are the same type."

这样就避免了由于程序员的疏忽而更改了set的key,从而导致了set中的元素不再有序。由此看来VS2010是符合最新的C++标准的。其实VS2008也是符合C++标准的,因为VS2008当时标准并没有明确说明set的key能否修改,所以VS2008两种都支持,它定义了一个宏_HAS_IMMUTABLE_SETS,缺省情况下这个宏被定义为0,一次set的key是可以被修改的,如果想得到一个key不能被修改的set,只需要定义宏_HAS_IMMUTABLE_SETS为1即可。这也说明了VS2008的态度,认可这种key可修改的set在多数情况下被使用,因为一般每人会去自定义随编译器分发的STL库。

 

最后,我想说的是在Effective STL的第22条中,scott指出切勿直接修改set或multiset中的键。之所以这样是因为会导致不可移植的代码,因为有的编译器允许修改key,而有的就不允许(比如gcc),并且其中还提到了怎样修改key才是安全的做法。现在C++标准已经明确的指出set中的key是immutable的,所以这个条款估计在下一版的时候会有些调整,不过里面提到的一些方法,如用强制转换来达到修改key的目的和其他的建议仍然有效,有兴趣的朋友可以看看。

 

参考文章:

1.    Effective STL 第22条

2.    http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#103

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值