Kshitij Shukla
Kshitij Shukla

Reputation: 133

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

I recently observed that modifying data inside a auto iterated vector is not yielding correct results for me. For example when i tried to sort elements of vector of vector, some elements were not sorted but the code ran successfully

vector<vector<int> > arr;
arr.push_back({38, 27});
for(auto v : arr)
{
    sort(v.begin(), v.end());
}

The output of above code after sorting is still 38, 27 after sorting. Whereas when i sort as sort(arr[0].begin(), arr[0].end()), the result is correct. I compiled using gcc.

Upvotes: 1

Views: 1608

Answers (4)

Slava
Slava

Reputation: 44258

I recently came to know that when a data inside range based for loop is modified, the result is undefined.

You got it quite wrong. It is Undefined Behavior if you modify container itself you iterating over (like adding or removing elements to it), not that you modify data it contains:

 std::vector<int> v( 10 );
 for( auto i : v ) v.push_back( 10 ); // UB as v is modified, new element inserted to it

vs:

 std::vector<int> v( 10 );
 for( auto &i : v ) i = 123; // totally fine you modify elements inside vector

Rest of your question is meaningless as it is based on this wrong assumption. The reason you do not observe data inside your vector change is different and already answered. But even if you fix your code and make it modify your container data it would be still fine.

Pedantic note: even statement that it is UB to modify container you iterating over is too generic. You may for example delete elements in std::list while iterating over it and still avoid UB. But of course such code should not be written at all, as it would be quite error prone and iterating over iterators range should be done in this case.

Upvotes: 2

eerorika
eerorika

Reputation: 238351

Why is modification of auto iterated data not a syntax error?

Because it is syntactically well formed to modify variables, whether the variable is a reference or not. Example:

int j = 0
int& i = j; // i refers to j
i = 42; // OK; j is modified


int j = 0
int i = j; // i is a copy of j
i = 42; // OK even though i is not reference
        // j is not modified; only i is

int j = 0
auto i = j; // i is a copy of j
i = 42; // OK; same as above except using auto deduced type
        // j is not modified

std::vector<int> int_vec(10);
for(int i : int_vec)
    i = 42; // OK; same as above except within a loop
            // the vector is not modified

for(auto i : int_vec) // i is a copy
    i = 42; // OK; same as above except using both auto and a loop
            // the vector is not modified

for(auto& i : int_vec) // i is a reference
    i = 42; // OK; elements of the vector are modified

I recently came to know that when a data inside range based for loop is modified, the result is undefined.

You've come across incorrect knowledge. Modifying variables inside range based for loop does not produce an undefined result.

There are some operations that may not be performed on the range that is being iterated, in particular those that invalidate iterators / references to elements of the iterated range. You may have been confused by this.

The program that you show has well-defined behaviour. However, you may have intended to sort the vector elements, which you have not done successfully. In order to do that, you must refer to the elements of the vector, rather than make a copy. That is achieved by using a refernce:

for( auto &v : arr )
          ^ this makes the variable a reference

Whereas when i sort as sort(arr[0].begin(), arr[0].end()), the result is correct.

The subscript operator returns a reference.

Upvotes: 3

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385144

Nothing here is undefined, and there is no reason for there to be a syntax error.

Your loop iterates the outer vector by value, then sorts the local copy of the inner vector. It's pointless, but it's not naughty.

I recently came to know that when a data inside range based for loop is modified, the result is undefined.

You can't structurally modify the thing you're iterating over, true, as that breaks the iteration.

But that's not what you did. Even if you'd written auto& v : arr, and thus modified the values of the inner vectors, you're still not performing any operation that disrupts the iteration of the outer vector arr.

Don't write arr.clear() inside the loop, though!

Why is modification of auto iterated data not a syntax error?

Even if your program had undefined behaviour, that's never a syntax error, and often not even a runtime error.

But if there were a blanket rule stating that no mutating operations could ever be performed inside a range-based for loop, rest assured the semantics of the language would probably mandate a compile-time error to stop you from doing it (like how you cannot build a program that modifies a const int directly).

Upvotes: 2

Demosthenes
Demosthenes

Reputation: 1535

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

Upvotes: 13

Related Questions