What Is the Advantage of Using Forwarding References in Range-Based For Loops

What is the advantage of using forwarding references in range-based for loops?

The only advantage I can see is when the sequence iterator returns a proxy reference and you need to operate on that reference in a non-const way. For example consider:

#include <vector>

int main()
{
std::vector<bool> v(10);
for (auto& e : v)
e = true;
}

This doesn't compile because rvalue vector<bool>::reference returned from the iterator won't bind to a non-const lvalue reference. But this will work:

#include <vector>

int main()
{
std::vector<bool> v(10);
for (auto&& e : v)
e = true;
}

All that being said, I wouldn't code this way unless you knew you needed to satisfy such a use case. I.e. I wouldn't do this gratuitously because it does cause people to wonder what you're up to. And if I did do it, it wouldn't hurt to include a comment as to why:

#include <vector>

int main()
{
std::vector<bool> v(10);
// using auto&& so that I can handle the rvalue reference
// returned for the vector<bool> case
for (auto&& e : v)
e = true;
}

Edit

This last case of mine should really be a template to make sense. If you know the loop is always handling a proxy reference, then auto would work as well as auto&&. But when the loop was sometimes handling non-proxy references and sometimes proxy-references, then I think auto&& would become the solution of choice.

Any reason to not use auto& for C++ range-based for-loops?

The two code snippets will result in the same code being generated: with auto, the compiler will figure out that the underlying type is int, and do exactly the same thing.

However, the option with auto is more "future-proof": if at some later date you decide that int should be replaced with, say, uint8_t to save space, you wouldn't need to go through your code looking for references to the underlying type that may need to be changed, because the compiler will do it for you automatically.

Usage of Range Based Loop for Vector of Pointer

It depends.

The first gives you a copy of the actual pointer for each loop cycle.
It follows that:

  • the pointer points to address in the memory where the object of ExampleClass resides
  • you have access to the object by dereferencing with *x
  • changing the pointing address of the pointer will not have any effect outside the scope of the for-loop

The second one gives you reference to the pointer stored in the actual element of the vector.
It follows that:

  • you can do the same things as with the first option
  • and you could let pointer point to a new address in memory and this is also going to take effect outside the scope of the for-loop

Important
If you use the last option you may end with a memory leak, if there is no pointer left pointing to the ExampleClass object created with new!

You have to delete every element of the vector created with new!

Therefore prefereable, is the usage of unique_ptr or smart_ptr! Using smart pointers leaves the ownership and destruction semantics up to them.

I would use the second one, because it saves you a copy, but the first one is saver and the copy of a pointer is inexpensive (see comment below by Olaf).

Or for (auto const& x : vec) ;-)

Why did the range based 'for' loop specification change in C++17?

Using

auto __begin = begin_expr, __end = end_expr;

requires both begin_expr and end_expr to return the same type. This means you cannot have a sentinel iterator type that is different from the beginning type. Using

auto __begin = begin_expr ;
auto __end = end_expr ;

fixes that issue while proving full backwards compatibility with C++14.

Need iterator when using ranged-based for loops

Use the old for loop as:

for (auto it = values.begin(); it != values.end();  ++it )
{
auto & value = *it;
//...
}

With this, you've value as well as iterator it. Use whatever you want to use.


EDIT:

Although I wouldn't recommended this, but if you want to use range-based for loop (yeah, For whatever reason :D), then you can do this:

 auto it = std::begin(values); //std::begin is a free function in C++11
for (auto& value : values)
{
//Use value or it - whatever you need!
//...
++it; //at the end OR make sure you do this in each iteration
}

This approach avoids searching given value, since value and it are always in sync.



Related Topics



Leave a reply



Submit