const_iterator 和 iterator 有什么区别,使用其中一个要比另一个更好的情况是什么?
const_iterator
不允许您更改它们指向的值,而普通的 iterator
则允许。
就像C++中的所有事物一样,始终优先使用 const
,除非有充分的理由使用常规迭代器(例如,您想利用它们不是 const
来更改指向的值)。
const
对象?这不是又一个糟糕设计的例子吗?请原谅,我只是真心想问一下。 - Max它们应该基本上是自解释的。如果迭代器指向类型为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_iterator是一个指向const元素的迭代器,因此虽然迭代器本身可以更新(例如增加或减少),但它所指向的元素不能被更改。
const iterator
和 const_iterator
之间的微妙差别,所以我点了赞。 - legends2k最小化的可运行示例
非const迭代器允许你修改它们所指向的内容:
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
方法中使用 this
时,const_iterator
是一个常见的情况:
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
变为常量,从而使 this->v
变成常量。
通常可以使用 auto
简化代码,但是如果开始传递这些迭代器,则需要考虑它们在方法签名中的使用。
与 const 和非 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
和 int
:尽可能使用 const 迭代器(当您不需要使用它们修改容器时),以更好地记录您的读取而不是修改的意图。
不幸的是,STL容器的许多方法都采用迭代器而不是const_iterators作为参数。因此,如果您有一个const_iterator,则无法说“在此迭代器指向的元素之前插入一个元素”(在我看来,这样说并不是概念上的const违规)。如果您仍想要这样做,则必须使用std :: advance()或boost :: next()将其转换为非const迭代器。例如,boost :: next(container.begin(),std :: distance(container.begin(),the_const_iterator_we_want_to_unconst))。如果container是std :: list,则该调用的运行时间为O(n)。
因此,在添加const的通常适用的"逻辑"位置时,请注意STL容器的例外情况。
然而,boost容器采用const_iterators(例如boost :: unordered_map :: erase())。因此,在使用boost容器时,可以更加"const agressive"。顺便问一下,有人知道STL容器何时会被修复吗?
vector
和 deque
的情况下,插入一个元素会使所有现有的迭代器失效,这并不是很符合 const
的概念。但我确实理解你的观点。这些操作受到容器的 const
属性保护,而不是迭代器。我也想知道为什么标准容器接口中没有 const 到非 const 迭代器的转换函数。 - Potatoswatterint const * foo;
,int * const foo;
和 int const * const foo;
三者都是有效和有用的,每个都有自己的用途。std::vector<int> const bar
应该与第二个相同,但不幸的是它经常被当作第三个来处理。问题的根本原因是我们无法说 std::vector<int const> bar;
,这意味着在向量中没有办法获得与 int const *foo;
相同的效果。 - dgnuff尽可能使用 const_iterator,当没有其他选择时才使用 iterator。
好的,让我先用一个非常简单的例子来解释一下,不使用常量迭代器。假设我们有一个随机整数集合"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;