Answers:
const_iterator
不允许您更改它们所指向的值,常规iterator
s则可以。
与C ++中的所有内容一样,始终首选const
,除非有充分的理由使用常规迭代器(即,您要使用它们不const
更改指向值的事实)。
他们几乎应该是不言自明的。如果迭代器指向类型为T的元素,则const_iterator指向类型为“ const T”的元素。
它基本上等同于指针类型:
T* // A non-const iterator to a non-const element. Corresponds to std::vector<T>::iterator
T* const // A const iterator to a non-const element. Corresponds to const std::vector<T>::iterator
const T* // A non-const iterator to a const element. Corresponds to std::vector<T>::const_iterator
const迭代器始终指向同一元素,因此迭代器本身就是const。但是它指向的元素不必是const,因此可以更改它指向的元素。const_iterator是指向const元素的迭代器,因此,尽管迭代器本身可以更新(例如,递增或递减),但指向的元素不能更改。
const iterater
和之间的微妙之处const_iterator
。
不幸的是,STL容器的许多方法都使用迭代器而不是const_iterators作为参数。因此,如果您具有const_iterator,则不能说“在此迭代器指向的元素之前插入一个元素”(我认为说这样的事情从概念上讲不是const违反)。如果您仍然希望这样做,则必须使用std :: advance()或boost :: next()将其转换为非常量迭代器。例如。boost :: next(container.begin(),std :: distance(container.begin(),the_const_iterator_we_want_to_unconst))。如果container是std :: list,则该调用的运行时间将为O(n)。
因此,在STL容器中,凡是在“逻辑上”添加const的通用规则都不太通用。
但是,boost容器使用const_iterators(例如boost :: unordered_map :: erase())。因此,当您使用boost容器时,您可以“ const agressive”。顺便说一句,是否有人知道是否或何时修复STL容器?
vector
and 的情况下deque
,插入一个元素会使所有现有的迭代器无效,这不是很严重const
。但我确实明白你的意思。此类操作受容器保护const
,而不是迭代器。而且我确实想知道为什么标准容器接口中没有const到nonconst迭代器转换函数。
int const * foo;
int * const foo;
和int const * const foo;
三者都是有效和有益的,每一个都有自己的方式。 std::vector<int> const bar
应该与第二个相同,但是不幸的是,它经常像第三个一样对待。问题的根本原因是我们不能说“ std::vector<int const> bar;
何时”意味着没有办法获得与int const *foo;
矢量相同的效果。
最少的可运行示例
非常量迭代器允许您修改它们指向的内容:
std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
*it = 1;
assert(v[0] == 1);
常量迭代器不:
const std::vector<int> v{0};
std::vector<int>::const_iterator cit = v.begin();
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;
如上所示,v.begin()
被const
重载,并根据容器变量的常量性返回iterator
或const_iterator
:
const_iterator
弹出的常见情况是在方法this
内部使用when的情况const
:
class C {
public:
std::vector<int> v;
void f() const {
std::vector<int>::const_iterator it = this->v.begin();
}
void g(std::vector<int>::const_iterator& it) {}
};
const
使this
const,这使this->v
const。
通常,您可以用忘记它auto
,但是如果您开始传递这些迭代器,则需要考虑它们作为方法签名。
就像const和non-const一样,您可以轻松地将非const转换为const,但反之则不行:
std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
// non-const to const.
std::vector<int>::const_iterator cit = it;
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;
// Compile time error: no conversion from const to no-const.
//it = ci1;
使用哪个:类似于const int
vs int
:只要您可以使用常量迭代器(不需要使用它们修改容器),便可以更好地记录您的阅读意图而无需进行修改。
(正如其他人所说的)const_iterator不允许您修改它指向的元素,这在const类方法内部很有用。它还可以让您表达自己的意图。
好吧,让我先用一个非常简单的示例来说明它,而无需使用常量迭代器,因为我们有随机整数集合“ randomData”的集合
for(vector<int>::iterator i = randomData.begin() ; i != randomData.end() ; ++i)*i = 0;
for(vector<int>::const_iterator i = randomData.begin() ; i!= randomData.end() ; ++i)cout << *i;
可以看出,在集合内部写入/编辑数据使用了普通迭代器,但出于读取目的,使用了常量迭代器。如果尝试在for循环的第一个中使用常量迭代器,则会得到错误。作为经验法则,请使用常量迭代器读取collection中的数据。