Saxtheowl
Saxtheowl

Reputation: 4658

Why using a reference as an iterator

I was learning about the emplace() of std::vector and stumble upon this code:

// vector::emplace
#include <iostream>
#include <vector>

int main ()
{
  std::vector<int> myvector = {10,20,30};

  auto it = myvector.emplace ( myvector.begin()+1, 100 );
  myvector.emplace ( it, 200 );
  myvector.emplace ( myvector.end(), 300 );

  std::cout << "myvector contains:";
  for (auto& x: myvector)
    std::cout << ' ' << x;
  std::cout << '\n';

  return 0;
}

I am wondering why in the for loop they use a reference auto& x instead of a simple copy, I tried without the & and it worked the same, is this a security to avoid a copy or a a performance trick ?

Upvotes: 2

Views: 706

Answers (2)

Gem Taylor
Gem Taylor

Reputation: 5613

The other difference between auto and auto& in this context is that auto& will let you modify the value in the vector. This may be an undesirable bug just waiting to happen. Ideally, if you are going to take a reference only for reading, you should take a const reference: const auto &

The benefit of using the reference when the vector contains objects that are more than a fundamental numeric or pointer type is it won't copy the whole object to a temporary. If the object has any deep copy semantics, or is perhaps a shared_ptr then there may be significant overhead that is totally avoided.

For a fundamental type the copy is usually very fast, so a single copy is preferred, but you can expect the compiler optimiser to do the "right thing" if asked to reference a fundamental and then use that reference numerous times, so for template programming you should favour the const-ref over the copy to keep the code simple when you don't know the type.

Upvotes: 3

Quimby
Quimby

Reputation: 19123

It's as simple as you said, it would be a copy. So it's indeed a performance trick, but for an int it won't be any faster, it might be even be slower. But had you had a std::vector<std::string> with million elements then it would make a big difference. You can try it yourself.

But, it's needed if you want to modify the contents of the iterated container. Without the reference, you would be changing the copy, not the element inside the container. The difference would be seen here:

std::vector<int> numbers1 = {1,2,3,4};
std::vector<int> numbers2 = {1,2,3,4};
for(auto& x: numbers1) ++x;
for(auto x: numbers2) ++x;
assert(numbers1!=numbers2); // True

Also I would recommend using auto&& instead of auto& because it will work better with temporaries, see e.g. this answer.

Upvotes: 1

Related Questions