Reputation: 31
A lot of questions related to for range has been asked around here, but I cannot find the version I need. So, I was reading this book called C Primer 5th edition, and while reading about Vectors I read a line which stated, we cannot use a range for if the body of the loop adds elements to the vector. But just before this line there was a code part written to add elements in the vectors during the run time, i.e.,
vector<int> v2; // empty vector
for (int i = 0; i != 100; ++i)
v2.push_back(i); // append sequential integers to v2
// at end of loop v2 has 100 elements, values 0 . . . 99
All I want to ask is that how can they both contradict to one another? Or are they completely different and not related to one another? If the second one is the condition can you explain me how this works? And if the former is correct can you please explain me why do the code part and the statement contradicted to one another?
Upvotes: 2
Views: 542
Reputation: 34628
The reason that (amongst other things) a range-based for loop shouldn't append elements is because behind the curtains, a range-based for loop is just a loop that iterates over the container's iterators from begin to end. And std::vector::push_back
will invalidate all iterators:
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.
Contrary to using iterators, however, the same cannot be said when indexing the vector, because even if push_back invalidats iterators, vec[3]
will always refer to the element at position 3
(assuming size() > 3
).
Furthermore, the loop you show does not even iterate over the vector's elements. It just adds more elements to an existing vector, and it is not a range-based for loop.
To be clear, a construct that would be a problem would be the following:
std::vector<int> vec(10); // 10 times a zero
vec[0] = 1;
for (int k: vec)
if (k == 1)
vec.push_back(2); // invalidates iterators!
While this, equivalent looking code, is legal:
std::vector<int> vec(10); // 10 times a zero
vec[0] = 1;
for (std::size_t i = 0; i < std::size(vec); ++i)
if (vec[i] == 1)
vec.push_back(2);
Upvotes: 2