7

The book i am reading offers this example when iterating over a vector

for (auto &e: v) {
  cout << e << endl;
}

Suppose v is declared as vector<int> v, in other words, we know that the type of elements inside this collection is int.

Is using auto in any way better or preferred to?

for (int &e: v) {
  cout << e << endl;
}

Why?

learnvst
  • 15,455
  • 16
  • 74
  • 121
James Leonard
  • 3,593
  • 5
  • 27
  • 32

2 Answers2

6

Yes. auto is preferred. Because if you change the declaration ofv from:

std::vector<int> v;  //before 

to this:

std::vector<float> v; //after

If you use int & in the for, then you have to change that as well. But with auto, no need to change!

In my opinion, working with auto is more or less like programming to interface. So if you do an operation += in the loop, and you don't really care about the type of the loop variable e as long as the type supports += operation, then auto is the solution:

for(auto & e : v)
{
      e += 2;
}

In this example, all you care about that the type of e supports += with int on the right hand side. It will work even for user-defined types, which has defined operator+=(int), or operator+=(T) where T is a type which supports implicit conversion from int . It is as if you're programming to interface:

std::vector<Animal*> animals;
animals.push_back(new Dog());
animals.push_back(new Cat());
animals.push_back(new Horse());

for(size_t i = 0 ; i < animals.size(); ++i)
{
       animals[i]->eat(food); //program to interface
}

Of course, you would like to write this loop as:

for(Animal * animal : animals)
{
       animal->eat(food); //still program to interface
}

Or simply this:

for(auto animal : animals)
{
       animal->eat(food); //still program to interface
}

It is still programming to interface.

But at the same time, the point in @David's comment is worth noting.

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 6
    This can be read both ways, it might be better to get a compilation error saying that an `int&` cannot be set from a `float&` than the compiler silently accepting code that was meant to work with ints... Not saying that it is a better idea to have `int&`, it all depends on what you do in the body of the `for` loop, if it does not depend on the exact type `auto` will be better – David Rodríguez - dribeas Aug 23 '12 at 02:59
  • @DavidRodríguez-dribeas: I think what you said is very unusual scenario. Usually, we have to change `int` to `float` in which case `auto` is a better solution. – Nawaz Aug 23 '12 at 03:03
  • 1
    Agreed. In most cases `auto&` will do... but I am not yet comfortable with types not being explicit everywhere :) (except when I really don't want to know!) – David Rodríguez - dribeas Aug 23 '12 at 03:10
  • I think the case for fundamentals varies greatly than from user-defined types. Fundamentals have this nasty habit of being implicitly converted to others, so David's point is very important here -- you can change the collection type, your loop will still compile, but produce nonsense results. – edA-qa mort-ora-y Aug 23 '12 at 05:00
  • @edA-qa mort-ora-y: If I change the collection type, then `for (int &e: v) ` will **not** compile. Note that it is `int & e`, not just `int e`. However, `for (int e: v)` will compile. – Nawaz Aug 23 '12 at 05:09
  • @Nawaz, indeed, so I guess explicitly typing in many cases still doesn't safe one from implicit conversion. :( – edA-qa mort-ora-y Aug 23 '12 at 05:13
  • @DavidRodríguez-dribeas: Please see the edit in my answer. I would like to know your opinion. – Nawaz Aug 23 '12 at 05:26
  • @Nawaz: Besides the syntax errors you mean ;) (The container in the second half of the answer holds `Animal*` but you are accessing it as if it was `Animal`) – David Rodríguez - dribeas Aug 23 '12 at 12:34
  • @DavidRodríguez-dribeas: Oops. Fixed. (Working in C# currently in office, which influenced the C++ syntax here also). – Nawaz Aug 23 '12 at 12:56
  • Also note, that if you change vector to list or set code with c+0x syntax will work, unless container has begin() and end() – galadog Aug 23 '12 at 12:59
  • @galadog: True, but then that has nothing to do with *this* discussion of `auto` vs explicit type. – Nawaz Aug 23 '12 at 13:00
1

On your first example, you have less dependency on what the elements of the vector are.

Suppose that in a month, you require that your vector stores larger integers, so you will have to use an std::vector<int64_t>, or some other, wider type. Now all of the code that iterates over that vector is invalid. You'll have to modify each:

for (int &e: v) {}

For a:

for (int64_t &e: v) {}

That is why it's better to just let auto deduce the internal type. That way you can modify the type stored in your vector for another, compatible one, and all your code will still work.

mfontanini
  • 21,410
  • 4
  • 65
  • 73