Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use vector<int>::iterator by reference but with error

#include<vector>
#include<iostream>
using namespace std;

int main()
{
    vector<int> vec = {1,2,3,4};
    for(auto & it = vec.begin(); it != vec.end(); ++it)
    {
        cout << *it << endl;
    }
}

Hello all, in C++ I use iterator by reference such as "auto & it" and the compiler return the error

" error: invalid initialization of non-const reference of type '__gnu_cxx::__normal_iterator >&' from an rvalue of type 'std::vector::iterator {aka __gnu_cxx::__normal_iterator >}' for(auto & it = vec.begin(); it != vec.end(); ++it) ".

I know "auto it = vec.begin()" works fine but as we all know pass by reference will improve the efficiency in C++, so why this error occurs when I use "auto & it"?

like image 663
MA Shengjing Avatar asked Jul 24 '17 06:07

MA Shengjing


2 Answers

so why this error occurs when I use "auto & it"?

See the return type of begin. It does not return a reference. It returns the iterator by value. Therefore the return value is a temporary in the rvalue category. Temporaries (rvalues) can not be bound to non-const lvalue references. This is what the error "invalid initialization of non-const reference of type ... from an rvalue of type ..." means.

Besides, modifying the begin pointer of the container would make little sense. It would have been silly for begin to return a reference.

Solution: Just create a copy of the iterator by declaring a non-reference value, just like you know works fine.

but as we all know pass by reference will improve the efficiency in C++

This is nonsense. An arbitrarily placed reference is unlikely to improve efficiency. Besides, you aren't trying to pass a reference here. You are trying to bind a reference to an object returned by a function.

Almost, if not always, iterators are very fast to copy (std::vector::iterator certainly is) and the indirection that you may potentially introduce with a reference may well be less efficient.

like image 195
eerorika Avatar answered Nov 15 '22 09:11

eerorika


The std::vector::begin returns an rvalue (a temporary object). You cannot take a reference to a temporary object with auto& (non-const lvalue reference). If you wish to take the mentioned return value by reference, you can use auto&& instead of auto& but I don't recommend it.

Using auto&& will create a mutable rvalue reference to the return value of std::vector::begin. This will extend its lifetime but I recommend to use auto only.

Using rvalue references won't improve the efficiency of your code, the compiler will optimize out the copy/move of interator object returned from std::vector::begin by value.

like image 36
Akira Avatar answered Nov 15 '22 09:11

Akira