Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Auto vs concrete type when iterating over vector?

Tags:

c++

int

c++11

auto

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?

like image 640
James Leonard Avatar asked Aug 23 '12 02:08

James Leonard


2 Answers

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.

like image 58
Nawaz Avatar answered Sep 23 '22 03:09

Nawaz


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.

like image 41
mfontanini Avatar answered Sep 23 '22 03:09

mfontanini