153

What is difference between these two regarding implementation inside STL. what is the difference regarding performance? I guess when we are traversing the vector in "read only wise", we prefer const_iterator, right?

Thank you.

Guy Avraham
  • 3,482
  • 3
  • 38
  • 50
user658266
  • 2,397
  • 4
  • 20
  • 14

3 Answers3

154

There is no performance difference.

A const_iterator is an iterator that points to const value (like a const T* pointer); dereferencing it returns a reference to a constant value (const T&) and prevents modification of the referenced value: it enforces const-correctness.

When you have a const reference to the container, you can only get a const_iterator.

Edited: I mentionned “The const_iterator returns constant pointers” which is not accurate, thanks to Brandon for pointing it out.

Edit: For COW objects, getting a non-const iterator (or dereferencing it) will probably trigger the copy. (Some obsolete and now disallowed implementations of std::string use COW.)

Yibo Yang
  • 2,353
  • 4
  • 27
  • 40
ysdx
  • 8,889
  • 1
  • 38
  • 51
  • 30
    Correct, except (const T*) is not a constant pointer, it is a pointer to const. – Brandon Apr 23 '14 at 21:03
  • 6
    There may be performance difference. Const iterator is a hint to the compiler so that it can assume the underlying object will not be changed through iterator manipulation. Compiler can use such hint to do more specific optimization. – WiSaGaN Apr 24 '14 at 06:56
  • 3
    @WiSaGaN: I do not think it is true. The underlying object could very well change by some other way and I do not think the compiler is allowed to assume that the underlying object does not change (http://www.gotw.ca/gotw/081.htm). – ysdx Apr 24 '14 at 07:07
  • 1
    I am not sure that there is no performance difference. Sometimes providing const-reference is much cheaper than providing a reference: in the latter case the container must be able to accept modification of the referenced value. In particularly, in (non-STL) copy-on-write containers the difference may be enormous. Ditto containers that trace changes. – Michael Dec 23 '14 at 01:37
  • 1
    @Michal: Yes, Indeed. I was thinking about plain STL-ish containers. For COW containers (or assimilated), you should expect to have a significant cost of deduplication/state-tracking for getting or dereferencing non-const iterators. – ysdx Jan 26 '15 at 19:47
  • 1
    @ysdx they do. simply they don't rely on C++ written `const`, they rely on their own "coloration" tags. – v.oddou Mar 12 '15 at 02:36
  • @v.oddou: Do you have reference on this? Are you talking about Qt containers? – ysdx Apr 30 '15 at 19:33
  • 1
    Yes, clang source code, `llvm/IR/Attribues.h` `Attribute::AttrKind::ReadOnly` the comment is `Function only reads from memory`. There are many of those coloration tags, they even merge and combine themselves hierarchically (i.e. they are call graph aware). The compiler is capable to know many things, for example if a function has no side effects... There is this nice doc about the optimizer passes here http://llvm.org/docs/Passes.html this gives a quick overview about stuff compilers are doing. – v.oddou May 11 '15 at 01:04
  • I can confirm that with colony (plf::colony) performance improvements were achieved simply via changing some internal code from iterator to const_iterator. The codegen size actually went Up when using const_iterator, but the resulting performance was greater. – metamorphosis Apr 30 '20 at 10:01
52

Performance wise there is no difference. The only purpose of having const_iterator over iterator is to manage the accessesibility of the container on which the respective iterator runs. You can understand it more clearly with an example:

std::vector<int> integers{ 3, 4, 56, 6, 778 };

If we were to read & write the members of a container we will use iterator:

for( std::vector<int>::iterator it = integers.begin() ; it != integers.end() ; ++it )
       {*it = 4;  std::cout << *it << std::endl; }

If we were to only read the members of the container integers you might wanna use const_iterator which doesn't allow to write or modify members of container.

for( std::vector<int>::const_iterator it = integers.begin() ; it != integers.end() ; ++it )
       { cout << *it << endl; }

NOTE: if you try to modify the content using *it in second case you will get an error because its read-only.

abhimanyuaryan
  • 3,882
  • 5
  • 41
  • 83
10

if you have a list a and then following statements

list<int>::iterator it; // declare an iterator
    list<int>::const_iterator cit; // declare an const iterator 
    it=a.begin();
    cit=a.begin();

you can change the contents of the element in the list using “it” but not “cit”, that is you can use “cit” for reading the contents not for updating the elements.

*it=*it+1;//returns no error
    *cit=*cit+1;//this will return error
Seeni
  • 1,518
  • 1
  • 14
  • 22
  • 1
    I think the OP was foremost interested in the *difference regarding performance* and was quite aware of the read-only character of the `const_iterator`. – mkl Mar 01 '17 at 15:41