Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 Range-based for-loop efficiency "const auto &i" versus "auto i"

In C++11, I can iterate over some container like so:

for(auto i : vec){    std::cout << i << std::endl; } 

But I know that this needlessly - needlessly, since I only need to print the values of vec - makes a copy of (EDIT: each element of) vec, so instead I could do:

for(auto &i : vec){    std::cout << i << std::endl; } 

But I want to make sure that the values of vec are never modified and abide by const-correctness, so I can do:

for(const auto &i : vec){    std::cout << i << std::endl; } 

So my question is: If I only need to look at the values of some container, wouldn't the very last loop (const auto &i) always be preferred due to the increased effieciency of not having an extra copy of (EDIT: each element of) vec?

I have a program that I'm developing in which I'm considering making this change throughout, since efficiency is critical in it (the reason I'm using C++ in the fist place).

like image 991
user2052561 Avatar asked Jun 10 '13 20:06

user2052561


People also ask

Does C have range-based for loops?

Range-based for loop in C++ It executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container.

Is range-based for loop faster?

Range-for is as fast as possible since it caches the end iterator[citationprovided], uses pre-increment and only dereferences the iterator once. Then, yes, range-for may be slightly faster, since it's also easier to write there's no reason not to use it (when appropriate).

What is const auto?

C++ auto auto, const, and referencesThe auto keyword by itself represents a value type, similar to int or char . It can be modified with the const keyword and the & symbol to represent a const type or a reference type, respectively. These modifiers can be combined.

Does a range-based for loop make a copy?

When used with a (non-const) object that has copy-on-write semantics, the range-based for loop may trigger a deep copy by (implicitly) calling the non-const begin() member function.


2 Answers

Yes. The same reason if you only ever read an argument you make the parameter const&.

T        // I'm copying this T&       // I'm modifying this const T& // I'm reading this 

Those are your "defaults". When T is a fundamental type (built-in), though, you generally just revert to const T (no reference) for reading, because a copy is cheaper than aliasing.


I have a program that I'm developing in which I'm considering making this change throughout, since efficiency is critical in it

  1. Don't make blind sweeping changes. A working program is better than a fast but broken program.
  2. How you iterate through your loops probably won't make much of a difference; you're looping for a reason, aren't you? The body of your loop will much more likely be the culprit.
  3. If efficiency is critical, you want to use a profiler to find which parts of your program are actually slow, rather than guess at parts that might be slow. See #2 for why your guess may be wrong.
like image 65
GManNickG Avatar answered Sep 18 '22 19:09

GManNickG


Disclaimer: In general the difference between auto and auto& is subtle, partly a matter of style, but sometimes also a matter of correctness. I am not going to cover the general case here!

In a range based for loop, the difference between

for (auto element : container) {} 

and

for (auto& element_ref : container) {} 

is that element is a copy of the elements in the container, while element_ref is a reference to the elements in the container.

To see the difference in action, consider this example:

#include <iostream>  int main(void) {     int a[5] = { 23,443,16,49,66 };      for (auto i : a) i = 5;            for (const auto& i : a) std::cout << i << std::endl;     for (auto& i : a) i = 5;        for (const auto& i : a) std::cout << i << std::endl;     } 

It will print

23 443 16 49 66 5 5 5 5 5 

because the first loop works on copies of the array elements, while the second actually modifies the elements in the array.

If you dont want to modify the elements then often a const auto& is more appropriate, because it avoids copying the elements (which can be expensive).

like image 25
463035818_is_not_a_number Avatar answered Sep 19 '22 19:09

463035818_is_not_a_number