const_iterators更快吗?

aJ.*_*aJ. 35 c++ iterator stl const-iterator

我们的编码指南更喜欢const_iterator,因为它们比正常情况下快一点iterator.看起来编译器会在您使用时优化代码const_iterator.

这真的是对的吗?如果是的话,内部真正发生的事情会变得const_iterator更快吗?

编辑:我写了一个小测试来检查const_iteratorvs iterator,发现不同的结果:

对于迭代10,000个对象const_terator,花费几毫秒(大约16毫秒).但并非总是如此.有两次相等的迭代.

unw*_*ind 75

如果没有别的,const_iterator 读取更好,因为它告诉任何人阅读代码"我只是迭代这个容器,而不是弄乱所包含的对象".

这是一个伟大的大胜利,更不用说任何性能差异了.

  • 在任何情况下,const_iterator都不会执行*更差*.你赢了头,尾巴你不输. (37认同)
  • 但是不回答问题,对吗? (2认同)

Dav*_*eas 25

我们使用的指南是:

总是喜欢const而非const

如果您倾向于使用const对象,那么您习惯于对所获得的对象仅使用常量操作,这与尽可能多地使用const_iterator一样多.

Constness具有病毒特性.一旦你开始使用它,它就会传播到你的所有代码.你的非变异方法变得不变,并且需要对属性仅使用常量操作,并且传递常量引用,这本身只会强制执行常量操作......

对我来说,使用常量迭代器而不是非常量迭代器(如果有的话)的性能优势远不如代码本身的改进那么重要.意味着(设计)非变异的操作不变的.


Mac*_*cke 18

它们适用于非平凡的容器/迭代器.直接养成你的习惯,当它重要时你不会失去性能.

此外,有几个理由喜欢const_iterator,无论如何:

  1. 使用const表示代码意图(即只读,不改变这些对象).
  2. 使用const(_iterator)可防止意外修改数据.(往上看)
  3. 有些库使用lack-const begin()来将数据标记为脏(即OpenSG),并将其同步发送到其他线程/网络,因此它具有真正的性能影响.
  4. 此外,允许您访问非const成员函数可能会产生您不想要的副作用(与上面的方式大致相同),例如从共享数据中分离写时复制容器.Qt for one,就是这样.

作为上面最后一点的一个例子,这里是Qt中qmap.h的摘录:

inline iterator begin() { detach(); return iterator(e->forward[0]); }
inline const_iterator begin() const { return const_iterator(e->forward[0]); }
Run Code Online (Sandbox Code Playgroud)

即使迭代器和const_iterator实际上是等效的(除了const), detach()如果有两个或更多对象使用它,也会创建数据的新副本.如果您只是要阅读数据,这是完全没用的,您可以通过使用来表明这些数据const_iterator.

当然,另一方面有数据点:

  1. 对于STL容器和许多简单复制语义容器,性能无关紧要.代码等价的.但是,能够编写清晰的代码并避免错误.
  2. Const是病毒式的,所以如果你在遗留的代码库中工作,其中const很难(或根本就没有)实现,你可能必须使用非const迭代器.
  3. 显然,一些前C++ 0x STL有一个错误,其中const_iterators不能用于擦除容器中的元素.


小智 14

我不明白他们为什么会这样 - constness是一个编译时检查.但显而易见的答案是写一个测试.

编辑:这是我的测试 - 它在我的机器上提供相同的时间:

#include <vector>
#include <iostream>
#include <ctime>
using namespace std;;


int main() {
    vector <int> v;
    const int BIG = 10000000;
    for ( int i = 0; i < BIG; i++ ) {
        v.push_back( i );
    }
    cout << "begin\n";
    int n = 0;
    time_t now = time(0);
    for ( int a = 0; a < 10; a++ ) {
        for( vector <int>::iterator it = v.begin(); it != v.end(); ++it ) {
            n += *it;
        }
    }
    cout << time(0) - now << "\n";
    now = time(0);
    for ( int a = 0; a < 10; a++ ) {
        for( vector <int>::const_iterator cit = v.begin(); cit != v.end(); ++cit ) {
            n += *cit;
        }
    }
    cout << time(0) - now << "\n";;

    return n != 0;

}
Run Code Online (Sandbox Code Playgroud)


ybu*_*ill 7

这取决于您使用的容器和实现.

是的,const_iterator 可能表现更好.

对于某些容器,const迭代器和可变迭代器的实现可能不同.我能想到的第一个例子是SGI的STL绳索容器.可变迭代器具有指向父绳索的附加指针以支持更新.这意味着浪费额外的资源用于引用计数更新+指向父绳索的指针的内存.请参阅此处实施说明.

但是,正如其他人所说,编译器不能单独使用const来进行优化.const只是授予对引用对象的只读访问权限,而不是说它是不可变的.对于像std::vector其一样的容器,其迭代器通常被实现为一个简单的指针,没有任何区别.


Shr*_*ree 6

我们的编码指南说更喜欢const_iterator

请看Scott Meyers的这篇文章.他解释了为什么人们应该更喜欢迭代器而不是const_iterator.

  • IMO Meyers错了.他基本上认为既然你不能将const_iterator转换为迭代器,因此不能通过const_iterator进行更改,你应该更喜欢迭代器.但事实上,你应该使用const_iterator来表达你不会尝试通过它进行更改. (17认同)
  • 这篇文章已经过时了.擦除/插入非const迭代器是标准中的一个错误,现在在C++ 0x中修复. (8认同)
  • @John Dibling < - Myers的文章毫无意义,他也可以说从不使用`const`,因为你无法改变`const`对象......这就是重点. (7认同)
  • 这是一篇相当古老的文章,从2001年开始到2003年标准之前.我想知道作者是否还有意见,我的猜测是他没有. (4认同)
  • 虽然有趣,速度不是该文章的论据. (3认同)