Our coding guidelines prefer const_iterator
, because they are a little faster compared to a normal iterator
. It seems like the compiler optimizes the code when you use const_iterator
.
Is this really correct? If yes, what really happens internally that makes const_iterator
faster?.
EDIT: I wrote small test to check const_iterator
vs iterator
and found varying results:
For iterating 10,000 objects const_terator
was taking a few milliseconds (around 16 ms) less. But not always. There were iterations in which both were equal.
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 bothiterator
andconst_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
loopconst_iterator
loop:I my experience, the compiler does not do any measureable optimization when using const iterators. Althought the statement "it could" is true and references are not defined to be pointers in the standard.
However, you can have two references to the same object, so one can be const, one non-const. Then, I guess the answers in this thread on restrict pointers apply: The compiler cannot know whether the object is changed by another thread, for example, or by some interrupt handling code.
If nothing else, a
const_iterator
reads better, since it tells anyone reading the code "I'm just iterating over this container, not messing with the objects contained".That's a great big win, never mind any performance differences.
container<T>::const_iterator::operator*
returns aconst T&
instead ofT&
, so the compiler can make the usual optimizations for const objects.when you benchmark any of this, make sure to use an appropriate optimization level -- you'll get wildly different timings using "-O0" versus "-O" and such.
They are for non-trivial containers/iterators. Get your habits straight and you won't lose performance when it does matter.
Also, there are several reasons to prefer const_iterator, no matter what:
begin()
to flag data as dirty (i.e. OpenSG) and will send it to other threads/over-network on sync, so there it has real performance implications.As an example of the last point above, here's an excerpt from qmap.h in Qt:
Even if iterator and const_iterator are practically equivalent (except for the
const
),detach()
creates a new copy of the data if there are two or more objects using it. This is completely useless if you're just going to read the data, which you indicate by usingconst_iterator
.Of course, there are data points in the other direction: