为什么调用erase
容器的const_iterator
成员函数会失败?
它适用于非const iterator
。
答案 0 :(得分:26)
这不会编译,因为container::iterator
和container::const_iterator
是两种不同的类型,且擦除的唯一(单参数)版本是:iterator erase(iterator);
不接受const_iterator
可被视为语言标准中的缺陷:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2350.pdf
这种限制没有特别的原因。迭代器仅用于在(可修改的)容器中指示位置,并且在insert
或erase
的情况下都不是修改的迭代器的“指针”(在在erase
的情况下它只是在概念上不存在,这对于const对象来说是正常的事情。)
当前标准表示“迭代器常量和容器常量”之间的混淆(这里也是其他答案),并且似乎const_iterator
可能在C ++ 0x中被erase
接受。
作为一种变通方法,您可以有效地从iterator
获取const_iterator
,因为容器首先必须是可变的。
下面的函数只适用于随机访问迭代器,因为使用其他类型的迭代器执行此操作可能有点太慢了。
#include <vector>
template <class Container>
typename Container::iterator to_mutable_iterator(Container& c, typename Container::const_iterator it)
{
return c.begin() + (it - c.begin());
}
int main()
{
int arr[] = {1, 5, 2, 5, 3, 4, 5, 1};
std::vector<int> vec(arr, arr + sizeof(arr) / sizeof(*arr));
for (std::vector<int>::const_iterator it = vec.begin(); it != vec.end(); ) {
//if (*it = 5) { //const_iterator prevents this error
if (*it == 5) {
it = vec.erase(to_mutable_iterator(vec, it));
}
else {
++it;
}
}
}
但是,重新构建代码可能会更好,因此您首先不需要const_iterator
。在这种情况下,最好使用std::remove
算法。如果你需要在擦除之前做更多的非变异工作,你可以将它提取到一个单独的方法等。
答案 1 :(得分:5)
我只想强调UncleBens,David Rodriguez和Ise Westeria发布的答案/评论的一般正确性。
无论当前(或以前)的C ++ 11之前的编译器的行为如何,const_iterator(应该)的const正确性会立即停止,因为它在语义上等于const T *(或T * const) - 请注意T本身可能是它自己的const类型! - 因此它有效地防止代码修改容器中引用的对象。
然而,因为在C ++中“删除”一个const指针是完全合法的(尝试它,它可以工作!),它应该是(并且行为已在C ++ 11中得到纠正)合法以及'擦除“来自容器的const迭代器,只要容器本身不是const。
似乎Visual Studio 2010已经通过“擦除”接受const_iterator来正确运行,这当然让我有些头疼来追踪其他一些bug,这导致我发表这篇文章,最终阐明了“擦除”的正确行为const_iterator“const correctness。
答案 2 :(得分:3)
关于constness,您可以将std::container<T>::const_iterator
视为const T*
。
答案 3 :(得分:2)
类型const_iterator
不能用于修改元素或容器的值。
答案 4 :(得分:-1)
这就是const_iterator的目的。当通过它访问的元素不应该被修改时,你使用它们。