7
#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"?

6
  • 4
    Search for the error string error: invalid initialization of non-const reference of type. There are many duplicates. Commented Jul 24, 2017 at 6:14
  • so why this error occurs when I use "auto & it"? Please pay close attention to the details of the compiler error. You are not allowed to initialize a non-const reference from an rvalue. Commented Jul 24, 2017 at 6:21
  • Just use a range based for for (auto &i : vec) Commented Jul 24, 2017 at 6:27
  • 3
    1. There is no pass by reference here; 2. Passing references doesn't necessarily improve performance; 3. Focusing on performance over correctness is a very bad move. (A program that does the wrong thing but does it very fast isn't as useful as you might think.) Commented Jul 24, 2017 at 7:16
  • 6
    As an aside, a vector::iterator is a small and highly optimized construct that is very cheap to construct and copy. Using a reference to it does not "improve the efficiency". At best it makes no difference. Commented Jul 24, 2017 at 7:22

3 Answers 3

18

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.

Sign up to request clarification or add additional context in comments.

Comments

5

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.

Comments

0

auto keyword gets the type as temporary object from the expression (std::vector::begin) since the it is temporary object and thus compiler cannot deduce to reference to it. auto& ( non-const lvalue)

The best approach in you case to use without reference auto var instead auto &var

If you are force to use Reference C++11 has introduced rvalue-reference, which can bind to temporary object change to && instead of & as below

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

4 Comments

I didn't downvote, but to me the difference seems obvious: Akira explained why the original code didn't work before giving the alternative, and then said that it's not a good idea. You just said 'do this instead' with no explanation or justification.
@underscore_d I saw his without edit version of answer it was two line say to use && instead of & later was changed in details btw if the ans is correct and not proper explanation can be asked to explain.anway its ok :-)
Akira was also downvoted before his edit. Rather than give excuses and compare to others, I suggest you improve your own answers instead. Then you won't get downvotes.
@Rohini Singh, thank you anyway. I think propose an answer with the explanation is better:)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.