The STL vector template defines element accessors as both const and non-const variants, for example:
reference operator[](size_type __n)
{return *(this->_M_impl._M_start + __n);}
const_reference operator[](size_type __n) const
{return *(this->_M_impl._M_start + __n);}
When does the compiler decide to use one version over the other? The vector itself is not defined as const, neither are the elements stored in it. So given two functions:
A f(int i) const
{ return myVector[i]; }
A f(int i)
{ return myVector[i]; }
My understanding is that the first would call the const version of operator[] and return a const A. The second calls the non-const version and returns a non-const A?
To me, the first version of f() seems to be the "correct" one to write since the function isn't altering anything, but it is perhaps surprising to the caller that it returns a const A. Surely if I wanted a const A returned, I should need to define f() as:
const A f(int i) const //Note the extra const at the start
{ return myVector[i]; }
Which would tell whoever is writing the caller to expect a const back.
So the extra const appears by magic? And what does the extra const get applied to if I'm using a boost::ptr_vector rather than std::vector? The data? The pointer? both?
This takes advantage of a tricky part of the function overload rules. First off, cv-qualifiers after the close parenthesis of a method prototype are just like cv-qualifiers on arguments, but they apply to the implicit this
argument. In a hypothetical C++ variant where you had to declare this
, the prototypes would be like so:
reference operator[](this_type this, size_type n);
const_reference operator[](const this_type this, size_type n);
Therefore, if the object you are calling the method on is const
, the second overload is a closer match and will be called. If it's not, the first overload will be called. So you get a const_reference
back if you index a const
container, and you get a reference
back if you index a non-const
container. The const_reference
object then enforces the read-only nature of the container it points into.
Sometimes const_reference
is the same as const reference
and sometimes it isn't; for the more complicated containers, a reference
is a class with nontrivial code, and that code has to be different for the read-only variety. The standard consistently uses const_reference
so that implementors have freedom to do that when they need to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With