Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's faster, iterating an STL vector with vector::iterator or with at()?

In terms of performance, what would work faster? Is there a difference? Is it platform dependent?

//1. Using vector<string>::iterator: vector<string> vs = GetVector();  for(vector<string>::iterator it = vs.begin(); it != vs.end(); ++it) {    *it = "Am I faster?"; }  //2. Using size_t index: for(size_t i = 0; i < vs.size(); ++i) {    //One option:    vs.at(i) = "Am I faster?";    //Another option:    vs[i] = "Am I faster?"; } 
like image 729
Gal Goldman Avatar asked Apr 22 '09 10:04

Gal Goldman


People also ask

Is std::vector fast?

A std::vector can never be faster than an array, as it has (a pointer to the first element of) an array as one of its data members. But the difference in run-time speed is slim and absent in any non-trivial program. One reason for this myth to persist, are examples that compare raw arrays with mis-used std::vectors.

Are iterators faster?

Iterators aren't intended to be faster, they're intended to be as fast, which they are, and significantly more generic.

What is the distinct advantage of using iterator over simple for looks?

Iterator and for-each loop are faster than simple for loop for collections with no random access, while in collections which allows random access there is no performance change with for-each loop/for loop/iterator.

Is vector faster than set C++?

Using a sorted vector instead of a set gives you faster lookup and much faster iteration, but at the cost of slower insertion. Insertion into a set, using set::insert, is proportional to log N, but insertion into a sorted vector, using insert_into_vector, is proportional to N.


1 Answers

Using an iterator results in incrementing a pointer (for incrementing) and for dereferencing into dereferencing a pointer.
With an index, incrementing should be equally fast, but looking up an element involves an addition (data pointer+index) and dereferencing that pointer, but the difference should be marginal.
at() also checks if the index is within the bounds, so it could be slower.

Benchmark results for 500M iterations, vector size 10, with gcc 4.3.3 (-O3), linux 2.6.29.1 x86_64:
at(): 9158ms
operator[]: 4269ms
iterator: 3914ms

YMMV, but if using an index makes the code more readable/understandable, you should do it.

2021 update

With modern compilers, all options are practically free, but iterators are very slightly better for iterating and easier to use with range-for loops (for(auto& x: vs)).

Code:

#include <vector>  void iter(std::vector<int> &vs) {     for(std::vector<int>::iterator it = vs.begin(); it != vs.end(); ++it)         *it = 5; }  void index(std::vector<int> &vs) {     for(std::size_t i = 0; i < vs.size(); ++i)         vs[i] = 5; }  void at(std::vector<int> &vs) {     for(std::size_t i = 0; i < vs.size(); ++i)         vs.at(i) = 5; } 

The generated assembly for index() and at() is identical godbolt, but the loop setup for iter() is two instructions shorter:

iter(std::vector<int, std::allocator<int> >&):         mov     rax, QWORD PTR [rdi]         mov     rdx, QWORD PTR [rdi+8]         cmp     rax, rdx         je      .L1 .L3:                              ; loop body         mov     DWORD PTR [rax], 5         add     rax, 4         cmp     rax, rdx         jne     .L3 .L1:         ret index(std::vector<int, std::allocator<int> >&):         mov     rax, QWORD PTR [rdi]         mov     rdx, QWORD PTR [rdi+8]         sub     rdx, rax         mov     rcx, rdx         shr     rcx, 2         je      .L6         add     rdx, rax .L8:                              ; loop body         mov     DWORD PTR [rax], 5         add     rax, 4         cmp     rdx, rax         jne     .L8 .L6:         ret 
like image 136
tstenner Avatar answered Oct 05 '22 03:10

tstenner