What is the difference between 'const auto& element' and 'auto element'? [duplicate] - c++

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).

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
Don't make blind sweeping changes. A working program is better than a fast but broken program.
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.
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.

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).

Imagine if your vector contains strings. Long strings. 5000 long strings. Copy them unnecessarily and you end up with a nicely written for loop that is awfully inefficient.
Make sure your code follows your intention. If you do not need a copy inside of the loop, do not make one.
Use a reference & as suggested above, or iterators.

Related

How should I loop over the elements of a C++ container in reverse order? [duplicate]

This question already has answers here:
Iterating C++ vector from the end to the beginning
(13 answers)
Closed 2 years ago.
Suppose I'm a newbie C++ programmer. I have a C++ container; say, a vector:
std::vector<int> vec { 12, 34, 56, 78 };
I know I can iterate over all of the elements with a simple loop:
for(std::vector<int>::size_type i = 0; i < vec.size(); i++) {
std::cout << vec[i] << '\n';
}
and maybe I've even learned a little about Modern C++, so I know I can use a ranged-for loop:
for(auto x : vec) {
std::cout << x << '\n';
}
But now, I want to iterate over the elements in reverse order. The range-based for loop won't work as such. With a plain loop, I have to be careful and avoid underflow, so perhaps something like this? :
for(std::vector<int>::size_type i = 0; i < vec.size(); i++) {
std::cout << vec[vec.size() - i] << '\n';
}
but - I don't like having the loop counter mean the opposite of what we're looking at. But if I started i at vec.size()-1, I would risk underflow after the last element. So I would need to do this, maybe?
for(std::vector<int>::size_type i = vec.size(); i > 0 ; i--) {
std::cout << vec[i - 1] << '\n';
}
well, that doesn't feel right either. What idioms should I use for reverse iteration, which are safe (i.e. difficult to get wrong) , aesthetically pleasing and reasonable terse?
Notes:
I tried to phrase the title to be as simple as possible (rather than saying "reverse-iterate a container").
Motivated by this question, where a naive reverse-iteration loop has a bug.
I do not want to make a copy of the container with the elements and reverse and iterate over that the usual way.
I didn't use auto& or const auto& in the loops above since newbie coders often don't know about them.
Well, first of all, about your two snippets: Part of the problem is that they're a bit bug prone for actual newbies - the integer underflow, off-by-one in the comparison, forgetting what i signifies and using it as a plain index etc. So I would definitely recommend something else. Also, those snippets may invoke vec.size() many times, which, if the compiler isn't optimizing well enough, would mean a bunch of redundant work.
Option 1: Use iterators
You can reverse-iterate over a container using a pair of iterators (std::rbegin and std::rend, and their constant variants) which represent the reversal of the container's order of elements. Here's what that looks like:
for(auto it = std::crbegin(vec); it != std::crend(vec); it++) {
std::cout << *it << '\n';
}
I made this option the first because it's (mostly) compatible with C++98. We didn't have std::rbegin() and std::crbegin() then, but we did have an rbegin() method for std::vector. std::crbegin() was introduced in C++11
Option 2: Using C++11 (and later) ranged-for loops
You can massage your container - without making a copy of it (although possibly with some payment of time), so that you can use the result in ranger for loop. The answers to this SO question describe several ways to do so, enabling the following code:
auto reverse_view = /* magic involving vec; and not making a copy */
for(auto x : reverse_view) {
std::cout << *it << '\n';
}
They involve either using an "infrastructural" library (namely Boost), or writing a few lines of code which return an iterator pair in an std::pair - which is enough for C++ to use in a ranged-for loop.
Option 3: Using ranged-for and C++20's ranges support
Finally, in C++20, this all becomes easier - with ranges support and std::ranges::reverse_view:
auto reverse_view = std::ranges::reverse_view{vec};
for (const auto& x : reverse_view) {
std::cout << x << '\n';
}
Performance note
Reverse-iterating can in some cases be expensive - because moving backwards, or finding the end of the container, is not always trivial or free. Think of a unidirectional list (where each element comes with a pointer to the next one) - whenever you want to go backwards, you need to traverse the whole list up to your current element to know where the previous element is located. Not all containers are like vectors...

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 ?
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.
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.

Difference between styles of iterating over vectors and other stl containers

Suppose there is an stl container, for the sake of simplicity I am going to use a vector declared as
After getting the answer I realized that it was because I wasn't actually iterating over int but a custom data structure template T, just making edits so someone in the future might find it easier to understand.
std::vector <T> vec;
Now there are two common methods to iterate over it.
1.
for(std::vector<T>::iterator it = vec.begin(); it != vec.end(); ++it)
{
/* std::cout << *it; ... */
}
2.
for(T t: vec)
{
/* std::cout << t; ... */
}
Now I always assumed that both these methods were more or less same under the hood and were supposed to have similar runtime, but recently in a competition on hackerearth the second one (My usual Goto) gave TLE on the last test case and just by switching to first method I managed to get all the cases passed, did I miss something that differentiates between them or it was just a coincidence (Since actual difference between their runtime was minute, just on different side of the limit). I couldn't find anything, so if you have any links or Insights please share.
This makes a copy of the variable from the vector into t:
for(int t: vec)
{
/* std::cout << t; ... */
}
For an int I don't think it will be much of a difference.
But if You're using a class with copy constructors,... You could try using a reference:
for(int& t: vec)
{
/* std::cout << t; ... */
}
And if it doesn't modify the variable, use a const int&

Simultaneously iterating over and modifying an unordered_set?

Consider the following code:
unordered_set<T> S = ...;
for (const auto& x : S)
if (...)
S.insert(...);
This is broken correct? If we insert something into S then the iterators may be invalidated (due to a rehash), which will break the range-for because under the hood it is using S.begin ... S.end.
Is there some pattern to deal with this?
One way is:
unordered_set<T> S = ...;
vector<T> S2;
for (const auto& x : S)
if (...)
S2.emplace_back(...);
for (auto& x : S2)
S.insert(move(x));
This seems clunky. Is there a better way I'm missing?
(Specifically if I was using a hand-rolled hash table and I could block it from rehashing until the end of the loop, it would be safe to use the first version.)
Update:
From http://en.cppreference.com/w/cpp/container/unordered_map/insert
If rehashing occurs due to the insertion, all iterators are invalidated. Otherwise iterators are not affected. References are not invalidated. Rehashing occurs only if the new number of elements is higher than max_load_factor() * bucket_count().
Could you mess with max_load_factor somehow to prevent rehashing?
Could you mess with max_load_factor somehow to prevent rehashing?
Yes, you can set the max_load_factor() to infinity to ensure no rehashing occurs:
#include <iostream>
#include <limits>
#include <unordered_set>
int main()
{
// initialize
std::unordered_set<int> S;
for (int i = 0; i < 8; ++i)
S.insert(i);
std::cout << "buckets: " << S.bucket_count() << std::endl;
// infinite max load factor => never need to rehash
const auto oldLoadFactor = S.max_load_factor();
S.max_load_factor(std::numeric_limits<float>::infinity());
for (const auto& x : S)
{
if (x > 2)
S.insert(x * 2);
}
// restore load factor, verify same bucket count
S.max_load_factor(oldLoadFactor);
std::cout << "buckets: " << S.bucket_count() << std::endl;
// now force rehash
S.rehash(0);
std::cout << "buckets: " << S.bucket_count() << std::endl;
}
Note that simply setting a new load factor does no rehashing, so those are cheap operations.
The rehash(0) bit works because it's a request that: 1) I get at least n buckets, and 2) I have enough buckets to satisfy my max_load_factor(). We just use zero to indicate we don't care for a minimum amount, we just want to rehash to satisfy our "new" factor, as if it was never changed to infinity.
Of course, this isn't exception-safe; if anything throws between the calls to max_load_factor(), our old factor is lost forever. Easily fixed with your favorite scope-guard utility or a utility class.
Note that you get no guarantees if you'll iterate over the new elements. You will iterate over the existing elements, but you may or may not iterate over the new elements. If that is okay (which per our chat it should be), then this will work.
For example, consider you iterate over an unordered set of integer and for each even integer x, insert x * 2. If those always get inserted just after your currrent position (by chance of implementation-detail and container state), you will never terminate the loop except through exceptions.
If you do need some guarantees, you need to with an alternate storage solution.
Modifying any container while you're iterating over it tends to get hairy - even if it's a simpler structure than a hash, or even if you can prevent it from re-hashing, re-balancing or whatever.
Even if it did work, by the way, there's an ambiguity: should your newly-inserted members be iterated over or not? Is it ok to include them in this iteration only sometimes (ie, only if they happen to end up after the current iterator)?
If you need to do this a lot, you could usefully wrap the container in a generic adapter that defers all the inserts until the end, but you're really finding a way to hide the code you already have.
I realized that it is conceptually the same as what you proposed but I think it looks actually reasonably slick:
std::vector<T> tmp;
std::copy_if(S.begin(), S.end(), std::back_inserter(tmp),
[](T const& value) { return ...; });
S.insert(std::make_move_iterator(tmp.begin()),
std::make_move_iterator(tmp.end()));

Iterate through a C++ Vector using a 'for' loop

I am new to the C++ language. I have been starting to use vectors, and have noticed that in all of the code I see to iterate though a vector via indices, the first parameter of the for loop is always something based on the vector. In Java I might do something like this with an ArrayList:
for(int i=0; i < vector.size(); i++){
vector[i].doSomething();
}
Is there a reason I don't see this in C++? Is it bad practice?
The reason why you don't see such practice is quite subjective and cannot have a definite answer, because I have seen many of the code which uses your mentioned way rather than iterator style code.
Following can be reasons of people not considering vector.size() way of looping:
Being paranoid about calling size() every time in the loop
condition. However either it's a non-issue or it can be trivially
fixed
Preferring std::for_each() over the for loop itself
Later changing the container from std::vector to other one (e.g.
map, list) will also demand the change of the looping mechanism,
because not every container support size() style of looping
C++11 provides a good facility to move through the containers. That is called "range based for loop" (or "enhanced for loop" in Java).
With little code you can traverse through the full (mandatory!) std::vector:
vector<int> vi;
...
for(int i : vi)
cout << "i = " << i << endl;
The cleanest way of iterating through a vector is via iterators:
for (auto it = begin (vector); it != end (vector); ++it) {
it->doSomething ();
}
or (equivalent to the above)
for (auto & element : vector) {
element.doSomething ();
}
Prior to C++0x, you have to replace auto by the iterator type and use member functions instead of global functions begin and end.
This probably is what you have seen. Compared to the approach you mention, the advantage is that you do not heavily depend on the type of vector. If you change vector to a different "collection-type" class, your code will probably still work. You can, however, do something similar in Java as well. There is not much difference conceptually; C++, however, uses templates to implement this (as compared to generics in Java); hence the approach will work for all types for which begin and end functions are defined, even for non-class types such as static arrays. See here: How does the range-based for work for plain arrays?
Is there any reason I don't see this in C++? Is it bad practice?
No. It is not a bad practice, but the following approach renders your code certain flexibility.
Usually, pre-C++11 the code for iterating over container elements uses iterators, something like:
std::vector<int>::iterator it = vector.begin();
This is because it makes the code more flexible.
All standard library containers support and provide iterators. If at a later point of development you need to switch to another container, then this code does not need to be changed.
Note: Writing code which works with every possible standard library container is not as easy as it might seem to be.
The right way to do that is:
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
it->doSomething();
}
Where T is the type of the class inside the vector. For example if the class was CActivity, just write CActivity instead of T.
This type of method will work on every STL (Not only vectors, which is a bit better).
If you still want to use indexes, the way is:
for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
v[i].doSomething();
}
Using the auto operator really makes it easy to use as one does not have to worry about the data type and the size of the vector or any other data structure
Iterating vector using auto and for loop
vector<int> vec = {1,2,3,4,5}
for(auto itr : vec)
cout << itr << " ";
Output:
1 2 3 4 5
You can also use this method to iterate sets and list. Using auto automatically detects the data type used in the template and lets you use it.
So, even if we had a vector of string or char the same syntax will work just fine
A correct way of iterating over the vector and printing its values is as follows:
#include<vector>
// declare the vector of type int
vector<int> v;
// insert elements in the vector
for (unsigned int i = 0; i < 5; ++i){
v.push_back(i);
}
// print those elements
for (auto it = v.begin(); it != v.end(); ++it){
std::cout << *it << std::endl;
}
But at least in the present case it is nicer to use a range-based for loop:
for (auto x: v) std::cout << x << "\n";
(You may also add & after auto to make x a reference to the elements rather than a copy of them. It is then very similar to the above iterator-based approach, but easier to read and write.)
There's a couple of strong reasons to use iterators, some of which are mentioned here:
Switching containers later doesn't invalidate your code.
i.e., if you go from a std::vector to a std::list, or std::set, you can't use numerical indices to get at your contained value. Using an iterator is still valid.
Runtime catching of invalid iteration
If you modify your container in the middle of your loop, the next time you use your iterator it will throw an invalid iterator exception.
Here is a simpler way to iterate and print values in vector.
for(int x: A) // for integer x in vector A
cout<< x <<" ";
With STL, programmers use iterators for traversing through containers, since iterator is an abstract concept, implemented in all standard containers. For example, std::list has no operator [] at all.
I was surprised nobody mentioned that iterating through an array with an integer index makes it easy for you to write faulty code by subscripting an array with the wrong index. For example, if you have nested loops using i and j as indices, you might incorrectly subscript an array with j rather than i and thus introduce a fault into the program.
In contrast, the other forms listed here, namely the range based for loop, and iterators, are a lot less error prone. The language's semantics and the compiler's type checking mechanism will prevent you from accidentally accessing an array using the wrong index.
don't forget examples with const correctness - can the loop modify the elements. Many examples here do not, and should use cont iterators. Here we assume
class T {
public:
T (double d) : _d { d } {}
void doSomething () const { cout << _d << endl; return; }
void changeSomething () { ++_d; return; }
private:
double _d;
};
vector<T> v;
// ...
for (const auto iter = v.cbegin(); iter != v.cend(); ++iter) {
iter->doSomething();
}
Note also, that with the C++11 notation, the default is to copy the element. Use a reference to avoid this, and/or to allow for original elements to be modified:
vector<T> v;
// ...
for (auto t : v) {
t.changeSomething(); // changes local t, but not element of v
t.doSomething();
}
for (auto& t : v) { // reference avoids copying element
t.changeSomething(); // changes element of v
t.doSomething();
}
for (const auto& t : v) { // reference avoids copying element
t.doSomething(); // element can not be changed
}
//different declaration type
vector<int>v;
vector<int>v2(5,30); //size is 5 and fill up with 30
vector<int>v3={10,20,30};
//From C++11 and onwards
for(auto itr:v2)
cout<<"\n"<<itr;
//(pre c++11)
for(auto itr=v3.begin(); itr !=v3.end(); itr++)
cout<<"\n"<<*itr;
int main()
{
int n;
int input;
vector<int> p1;
vector<int> ::iterator it;
cout << "Enter the number of elements you want to insert" << endl;
cin >> n;
for (int i = 0;i < n;i++)
{
cin >> input;
p1.push_back(input);
}
for(it=p1.begin();it!=p1.end();it++)
{
cout << *it << endl;
}
//Iterating in vector through iterator it
return 0;
}
conventional form of iterator
If you use
std::vector<std::reference_wrapper<std::string>> names{ };
Do not forget, when you use auto in the for loop, to use also get, like this:
for (auto element in : names)
{
element.get()//do something
}