Our coding guidelines prefer const_iterator
, because they are a little faster compared to a normal iterator
. It seems like the compiler optimizes t
I can't see why they would be - constness is a compile time check. But the obvious answer is to write a test.
Edit: Here is my test - it gives identical timings on my machine:
#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;
}
It depends on the container and implementation you use.
Yes, const_iterator
may perform better.
For some containers the implementation of const iterators and mutable iterators may differ. A first example I can think of is the SGI's STL rope container. The mutable iterator has additional pointer to the parent rope in order to support updates. This implies additional resources wasted for reference counting updates + memory for the pointer to the parent rope. See the implementation notes here.
However, as others said, the compiler cannot use const
by itself to do optimization. const
just grants read-only access to the referenced object rather than saying that it is immutable. For a container like std::vector
, whose iterators are usually implemented as a simple pointers, there won't be any difference.
Our coding guidelines say prefer const_iterator
Have a look at this article by Scott Meyers here. He explains why one should prefer iterator over const_iterator.
They should be identical, as constness is a compile-time check.
To prove to myself there were no quirks, I took anon's code, modified it to use clock_gettime
, added an outer loop to avoid caching biases, and ran it many times. Results were surprisingly inconsistent - up and down by 20% (no idle boxes available) - but minimum times for both iterator
and const_iterator
were practically identical.
I then got my compiler (GCC 4.5.2 -O3) to generate assembly output and visually compared the two loops: identical (except that the order of a couple register loads was reversed)
iterator
loop
call clock_gettime
movl 56(%esp), %esi
movl $10, %ecx
movl 60(%esp), %edx
.p2align 4,,7
.p2align 3
.L35:
cmpl %esi, %edx
je .L33
movl %esi, %eax .p2align 4,,7
.p2align 3
.L34:
addl (%eax), %ebx
addl $4, %eax
cmpl %eax, %edx
jne .L34
.L33:
subl $1, %ecx
jne .L35
leal 68(%esp), %edx
movl %edx, 4(%esp)
leal 56(%esp), %esi
movl $1, (%esp)
const_iterator
loop:
movl 60(%esp), %edx
movl $10, %ecx
movl 56(%esp), %esi
.p2align 4,,7
.p2align 3
.L38:
cmpl %esi, %edx
je .L36
movl %esi, %eax
.p2align 4,,7
.p2align 3
.L37:
addl (%eax), %ebx
addl $4, %eax
cmpl %eax, %edx
jne .L37
.L36:
subl $1, %ecx
jne .L38
leal 68(%esp), %edx
movl %edx, 4(%esp)
leal 56(%esp), %esi
movl $1, (%esp)
container<T>::const_iterator::operator*
returns a const T&
instead of T&
, so the compiler can make the usual optimizations for const objects.
"Const-ness", like access restriction (public, protected, private), benefits the programmer more than it assists with optimization.
Compilers can't actually optimize for as many situations involving const as one might think, for many reasons (such as const_cast, mutable data members, pointer/reference aliasing). The most relevant reason here though is that, just because a const_iterator doesn't allow modifying the data it refers to, doesn't mean that that data can't be changed via other means. And if the compiler can't determine that the data is read-only, then it can't really optimize much more than it would for the non-const iterator case.
More info and examples can be found at: http://www.gotw.ca/gotw/081.htm