C ++ STL中的const_iterator和非const迭代器有什么区别?


139

a const_iterator和an 之间有什么区别,iterator您将在哪里使用另一个?


1
好吧,名称const_iterator听起来像是迭代器是const,而此迭代器指向的是实际的const。
talekeDskobeDa

Answers:


124

const_iterator不允许您更改它们所指向的值,常规iterators则可以。

与C ++中的所有内容一样,始终首选const,除非有充分的理由使用常规迭代器(即,您要使用它们不const更改指向值的事实)。


8
在一个完美的世界中,情况就是如此。但是使用C ++ const只能和编写代码的人一样好:(
JaredPar

可变的存在是有很好的理由的。它很少使用,在Google代码搜索中,有效使用的百分比似乎很高。关键字是一个非常强大的优化工具,它不像删除它会提高const正确性(coughpointerscoughandcoughreferencescough
coppro

2
更像是强大的hack。在我见过的所有使用'mutable'关键字的实例中,除了一个以外,所有其他实例都可以准确地表明代码编写不当,并且需要使用可变的代码来解决这些缺陷。
John Dibling

7
它的确有合法用途,例如在const类中缓存长时间计算的结果。另一方面,这几乎是我在近二十年的C ++开发中唯一使用可变的方法。
极客头

使用const_iterator的通用示例是当迭代器为右值时
talekeDskobeDa,

40

他们几乎应该是不言自明的。如果迭代器指向类型为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元素的迭代器,因此,尽管迭代器本身可以更新(例如,递增或递减),但指向的元素不能更改。


1
“ const迭代器始终指向相同的元素”,这是不正确的。
John Dibling

2
为何如此?请注意缺少下划线。我正在将const std :: vector <T> :: iterator类型的变量与std :: vector <T> :: const_iterator进行对比。在前一种情况下,迭代器本身是const,因此无法修改,但它引用的元素可以自由修改。
jalf

4
知道了 是的,我想念缺少的下划线。
John Dibling

3
@JohnDibling赞扬了const iterater和之间的微妙之处const_iterator
legends2k 2015年

8

不幸的是,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))。如果containerstd :: list,则该调用的运行时间将为O(n)

因此,在STL容器中,凡是在“逻辑上”添加const的通用规则都不太通用。

但是,boost容器使用const_iterators(例如boost :: unordered_map :: erase())。因此,当您使用boost容器时,您可以“ const agressive”。顺便说一句,是否有人知道是否或何时修复STL容器?


1
这可能是一个见解的问题。在vectorand 的情况下deque,插入一个元素会使所有现有的迭代器无效,这不是很严重const。但我确实明白你的意思。此类操作受容器保护const,而不是迭代器。而且我确实想知道为什么标准容器接口中没有const到nonconst迭代器转换函数。
Potatoswatter 2010年

你是正确的Potatoswatter,我是绝对的,它是一个见仁见智的随机访问容器的问题container.begin()+(the_const_iterator_we_want_to_unconst - container.begin())O(1)反正。我还想知道为什么非随机访问容器没有转换功能,但是也许有充分的理由吗?您是否知道出于某种原因非随机访问容器的函数不使用const_iterators
Magnus Andermo,2010年

“在我看来,从概念上讲,这样的事情从概念上讲不是const违背的”-这是一个非常有趣的评论,我对此主题有以下想法。通过简单的指针,可以说int const * foo; int * const foo;int const * const foo;三者都是有效和有益的,每一个都有自己的方式。 std::vector<int> const bar应该与第二个相同,但是不幸的是,它经常像第三个一样对待。问题的根本原因是我们不能说“ std::vector<int const> bar;何时”意味着没有办法获得与int const *foo;矢量相同的效果。
dgnuff

5

尽可能使用const_iterator,别无选择时使用迭代器


4

最少的可运行示例

非常量迭代器允许您修改它们指向的内容:

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重载,并根据容器变量的常量性返回iteratorconst_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使thisconst,这使this->vconst。

通常,您可以用忘记它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 intvs int:只要您可以使用常量迭代器(不需要使用它们修改容器),便可以更好地记录您的阅读意图而无需进行修改。



0

好吧,让我先用一个非常简单的示例来说明它,而无需使用常量迭代器,因为我们有随机整数集合“ 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中的数据。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.