Setting Vector Elements in Range-Based for Loop

Setting vector elements in range-based for loop

Change this loop statement

for(auto n: *CTdata)

to

for(auto &n : *CTdata)

that is you have to use references to elements of the vector.

Erasing vector elements while in a range-based loop vs. standard loop

In the first case, for each iteration std::vector::size function is being called. Thus, if you delete all the elements in the first iteration, std::vector::size function which is called before the start of second iteration will return 0. Therefore, second iteration won't happen because the condition i < test.size() is not satisfied.

In the second case, range-based for loop uses iterators instead of std::vector::size function. When you call std::vector::erase you invalidate all the iterators including the end() iterator. Therefore, second case is actually UB (Undefined Behavior) and you should never rely on that.

From the docs:

std::vector::erase

... Invalidates iterators and references at or after the point of the
erase, including the end() iterator.

About using range based for loop over a vector of vectors

each element of e is a vector, each element of e[node] is int.

Why doesn't range-based for loop modifiy container elements?

Your for loop copies v, then sorts it. The original is untouched. What you want is for (auto &v : arr).

Can range based for loop work for assignment?

Is it possible to use/implement a ranged base loop to assign numbers to an array?

Yes, use a reference:

for (auto & i : X){
// ^
i = 1;
}

vectors in range based for loop

for(auto i : anotherVector)
cout << anotherVector[i] << endl;

This code doesn't do what you think it does. The range-based for loop iterates over values, not over indices. In other words, the loop variable (i) is assigned all ements of the vector in turn.

To replicate the functionality of your first loop, you need this:

for (auto i : anotherVector)
cout << i << endl;

What your original code was doing was take an element of the vector, and use it to index into the vector again. That's why the numbers were off by one (since the vector held number n + 1 at position n). Then, the final output (81 in your case) was effectively random and the result of Undefined Behaviour—you were reaching past the end of the vector.

C++ range-based for loop and copy of element

As mentioned in the comment by @Fureeish one problem with the second version is inserting to the subsets vector while iterating over the subsets vector.

for (vector<int> subset : subsets)
{
subset.push_back(current_num);
subsets.push_back(subset); // Should not modify vector while iterating on it
}

The range statement expands to something like:

{

auto && __range = range_expression ;
for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin) {

range_declaration = *__begin;
loop_statement
}
}

The __end expression is expanded before the iterations. For a vector this could be calculating the address at vector.data[size]. If the loop pushes new elements into the vector, the __end expression is no longer correct.

If you iterated over a copy of the vector instead, the range statement would work. For example:

    for (vector<int> subset : vector<vector<int>>(subsets))
{
subset.push_back(current_num);
subsets.push_back(subset);
}

Fill a vector of pointers with a range-based for loop

Take the elements by reference:

for (auto& r : v)
pv.push_back(&r);

Your original range-based for loop iterates the vector by value, making each i a fresh copy of each item. The expression &i therefore does not retrieve the address of element inside v.

Iterating by reference, each r refers to the very element inside v, and thus the address-of expression &r correctly retrieve the element's address.

Range based for loop: Iterate over vector extended with one element

It can be done using the upcoming ranges feature.

Here's an example using Eric Niebler's range-v3 library:

#include <iostream>
#include <vector>

#include <range/v3/view/concat.hpp>
#include <range/v3/view/single.hpp>

int main() {
std::vector<int> a = {1, 5, 3};
int additional = 6;
for (auto i : ranges::concat_view(ranges::single_view{additional}, a)) {
std::cout << i;
}
}

See it live!

by using views, all iterator operations are lazy, and no extra memory is used (e.g.: no extra vectors/arrays are created)

Or, without the for loop:

ranges::copy(ranges::concat_view(ranges::single_view{additional}, a), ranges::make_ostream_joiner(std::cout, ","));

See it live!

(Honestly, I like the for version better, though)

Standard-compliant solution

There's a small issue with the solution above: concat_view did not make it into C++20. If you want a strictly compliant solution, you may want to create your own version, or use join_view instead:

#include <iostream>
#include <vector>

#include <ranges>

int main() {
std::vector<int> a = {1, 5, 3};
int additional = 6;

std::vector v{{additional}, a};

for(int i : std::ranges::join_view{v}) {
std::cout << i;
}
}


Related Topics



Leave a reply



Submit