It's because the rationale is that performance should be optimized for iterators, not indices.
(In other words, performance should be optimized for begin()
/end()
, not size()
/operator[]
.)
Why? Because iterators are generalized pointers, and thus C++ encourages their use, and in return ensures that their performance matches those of raw pointers when the two are equivalent.
To see why it's a performance issue, notice that the typical for
loop is as follows:
for (It i = items.begin(); i != items.end(); ++i)
...
Except in the most trivial cases, if we kept track of sizes instead of pointers, what would happen is that the comparison i != items.end()
would turn into i != items.begin() + items.size()
, taking more instructions than you'd expect. (The optimizer generally has a hard time factoring out the code in many cases.) This slows things down dramatically in a tight loop, and hence this design is avoided.
(I've verified this is a performance problem when trying to write my own replacement for std::vector
.)
Edit: As Yakk pointed out in the comments, using indices instead of pointers can also result in the generation of a multiplication instruction when the element sizes aren't powers of 2, which is pretty expensive and noticeable in a tight loop. I didn't think of this when writing this answer, but it's a phenomenon that's bitten me before (e.g. see here)... bottom line is, in a tight loop everything matters.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…