Invalidating loop bounds - c++

I've recently inherited a project primarily done in C++, so this is my first real exposure to it. I'm wondering if I may have a problem erasing a vector's elements from within a loop bounded by the vector's begin() and end().
Here's (essentially) what I've been trying to do:
for (vector<double>::iterator i = distance.begin(); i < distance.end(); i++) {
for (vector<double>::iterator j = i + 1; j < distance.end(); j++) {
/* code to assemble *i, *j, and some other values, say *x & *y
(also iterators) assumed to be in the distance vector */
vector< vector<double >::iterator remove;
remove.push_back(i); remove.push_back(j);
remove.push_back(x); remove.push_back(y);
sort(remove.begin(), remove.end());
for (int r = remove.size() - 1; r >= 0; r--) {
distance.erase(remove.at(r));
}
}
}
For what I'm testing it on, this appears to work. However, I'm concerned that's just because of a fluke and this solution shouldn't be used. Does distance.end() get reset at the beginning of each loop, or does C++ just check with the initial value?

for-loop will evaluate i < distance.end() on each loop. The problem is in distance.erase, it will invalidate i, so the result of i++ is undefined.

distance.end() is always accurate to the current state of the vector.
for() loops always re-evaluate the condition on every loop.

Related

For loop using pointers to traverse array not working properly

For my homework problem I must use pointers to traverse arrays. When I try to store 3 "name" values into member variables of an array of an Object called RentalAgency, I find that it stores the value, but never increments. Therefore the last value given is stored in the first index and the next two are empty.
RentalAgency *agencies_ptr = agencies;
for(int i = 0; i < 3;i++,++agencies_ptr){
infile.get((agencies->name),MAX_SIZE,space);
}
Where agencies is an array of Objects
If the input is Hertz, Alamo, and Budget, it should output Hertz, Alamo, and Budget.
The actual output is just Budget.
Just write
for(int i = 0; i < 3; i++){
infile.get( agencies_ptr[i].name, MAX_SIZE, space );
}
You are desreferencing agencies, not agencies_ptr (and the parenthesis are not needed):
RentalAgency *agencies_ptr = agencies;
for(int i = 0; i < 3; ++i, ++agencies_ptr)
infile.get(agencies_ptr->name, MAX_SIZE, space);
But a more idiomatic way of traversing a "range" is this (it stands for iterator):
RentalAgency *agencies_it = agencies;
RentalAgency *agencies_end = agencies_it + 3;
for(; agencies_it != agencies_end; ++agencies_it)
infile.get(agencies_it->name, MAX_SIZE, space);
It's cleaner, express intent better and is more familiar to see among experienced programmers.

in a for loop, does the variable used in the condition get checked at every iteration, or only the first?

I want to run a loop on a std::vector<std::vector<int>> array to delete desired elements.
I'm using for (i = 0; i < array.size(); i++)
is it safe to invoke array.erase() from within the loop?
In my head I assume for checks array.size() at every iteration, but maybe it only does it once at initiation. If it did, for (i = 0; i < &array.size(); i++) would work a fine solution, would it not?
Thank you.
is it safe to invoke array.erase() from within the loop?
Yes, it is perfectly safe. Compiler is allowed to optimize the check by calling array.size() only once out of the loop only if it can prove that vector is not modified inside the loop, e,g, if the vector is constant and thus not modifiable. In that case optimizing that way won't change observable behavior. But since you are calling erase inside the loop compiler is not allowed to call array.size() only once.
In general, an implementation is allowed to do only those code transformations that do not change observable behavior. This is called as-if rule.
I'm using for (i = 0; i < array.size(); i++)
is it safe to invoke array.erase() from within the loop?
It is safe but it is going throw your iteration logic off.
Let's say you have {1 2 3 4 5} in array.
You removed 2 from the array. At that time, i is 1. After removing 2, array is now {1 3 4 5}. You increment i in the for statement, which makes i 2. You will end up accessing 4 from the array in the loop, which skips 3 altogether.
In my head I assume for checks array.size() at every iteration, but maybe it only does it once at initiation.
No, it does that check in every iteration of the loop.
If it did, for (i = 0; i < &array.size(); i++) would work a fine solution, would it not?
Not sure where you got that idea but it's wrong. Don't even go there.
You can use:
for ( i = 0; i < array.size(); /* Don't increment here */ )
{
// Code
// Check for erase.
if ( check-for-erase-logic )
{
// Erase item
// Don't increment iteration counter.
}
else
{
// Increment iteration counter.
++i;
}
}
i < array.size() is the condition part of the for statement which is evaluated before each iteration, and if it yields false, the loop is exited. This answers the question in your title.
However, erase will invalidate iterators. So you should be careful. It is better to use algorithms to achieve this. One way would be the remove/erase idiom.
In contrast to a range for loop aka for (T element : container), in normal loops the condition is checked every time. So yes your normal for loop is safe.
However be aware of iterator, references and pointer invalidation after erase, and also that your i could be outside of the new range after the erase
Here some do's and dont's
#include <iostream>
#include <vector>
int main() {
using T = std::vector<int>;
std::vector<T> vector{{3,4},{3,5},{5,9}};
for (size_t i = 0; i < vector.size(); ++i) {
auto &vec2 = vector.at(2);
if (i == 2) {
vector.erase(vector.begin() + 1); //fine}
}
auto &v = vector[i]; //NOT FINE UNDEFINED BEHAVIOUR!
if (i < vector.size()) //Could be optimized out by compiler because of UB!, when compiling with line above,
// as the for check
break;
std::cout << vec2.at(1); //Also UNdefined behaviour since many things are invalidated after erase
}
for (auto v : vector) {
vector.erase(vector.begin()); //Also NOT ALLOWED since for ranges are allowed to cache iterators
}
}

How to get int position of vector loop

How to get int position of this loop? Thank you.
auto a = vect.begin();
auto b = vect2.begin();
auto c = vect3.begin();
for (; a != vect.end() && b != vect2.end() && c != vect3.end(); a++, b++, c++) {
}
I need to print values of other variable, but I need to get actual unsigned int position of this vector loop.
I need to print double vector using this position of this vector.
And how to get the last index of vector.
My problem is for for loop with multiple vectors and getting index from it next to use only last of indexes.
As Angew shows, a simple indexed loop may be preferable when you need indices.
However, it is possible to get the index from an iterator as well:
auto a = vect.begin();
auto b = vect2.begin();
auto c = vect3.begin();
for (/*the loop conditions*/) {
auto index = a - vect.begin();
}
It is also possible to get the index of a forward iterator using std::distance, but it would be unwise to use it in a loop, since the complexity will be linear for non-random-access iterators.
In the case of forward iterators (and generic code that must support forward iterators), you can write a loop which has both the index variable, and the iterators.
P.S. it is potentially preferable to use pre-increment with iterators. Probably only matters in debug build.
It's simple: if you need indices, don't use iterators:
for (
size_t idx = 0, idxEnd = std::min({vect.size(), vect2.size(), vect3.size()});
idx < idxEnd;
++idx
)
{
auto& obj1 = vect[idx];
auto& obj2 = vect2[idx];
auto& obj3 = vect3[idx];
}
(The above code initialises idxEnd once at the start of the loop, so that it's not needlessly recomputed at each iteration. It's just an optimisation).

Issues of getting stuck into infinite loop while iterating through vectors

I want to search through a vector of pairs and in order to do so..i am doing the following:
vector<pair<double ,double> > vec_pairs;
for(vector<unsigned int>::size_type j = 0; j != vec_pairs.size(); j++ )
{
if(vec_pairs[j].first==12.6)
{
int z=7;
continue;
}
}
However my problem is...upon doing this...i am getting stuck in an infinite loop...
Can anyone help me in resolving the problem
First of all, the code that you posted works well 'as it is'.
The only reason for such type of a code to go into infinite loop is to modify j inside the loop.
If you increase j inside the loop, you will probably not get stuck because you will go out of bonds and might have your code crash.
for(vector<unsigned int>::size_type j = 0; j != vec_pairs.size(); j++ )
{
if(vec_pairs[j].first==12.6)
{
j++;//You will go out of vector bonds and might get an error here.
continue;
}
}
However, if you do something like this:
for(vector<unsigned int>::size_type j = 0; j != vec_pairs.size(); j++ )
{
if(vec_pairs[j].first==12.6)
{
j--;//j is decreased each time you get in here, so you will be stuck on one element,
continue;
}
}
Then you will get stuck inside, because when you go into the if statement (say, on element 7), j will decrease to 6, then you will continue the loop, j will increase back to 7, you will go inside the if again, and so on.
I have tested your code in codepad. Check it here! And it is working fine. Check the value of the variable j while debugging. As SingerOftheFall said, It might be getting decremented or reset somewhere. It can also go on an infinite loop if you are adding elements inside the loop which increase the value of vec_pairs.size() and the condition j != vec_pairs.size() will never be true in that case. Can't find anything wrong in the code you given.

Vector push_back in while and for loops returns SIGABRT signal (signal 6) (C++)

I'm making a C++ game which requires me to initialize 36 numbers into a vector. You can't initialize a vector with an initializer list, so I've created a while loop to initialize it faster. I want to make it push back 4 of each number from 2 to 10, so I'm using an int named fourth to check if the number of the loop is a multiple of 4. If it is, it changes the number pushed back to the next number up. When I run it, though, I get SIGABRT. It must be a problem with fourth, though, because when I took it out, it didn't give the signal.
Here's the program:
for (int i; i < 36;) {
int fourth = 0;
fourth++;
fourth%=4;
vec.push_back(i);
if (fourth == 0) {
i++;
}
}
Please help!
You do not initialize i. Use for (int i = 0; i<36;). Also, a new variable forth is allocated on each iteration of the loop body. Thus the test fourth==0 will always yield false.
I want to make it push back 4 of each number from 2 to 10
I would use the most straight forward approach:
for (int value = 2; value <= 10; ++value)
{
for (int count = 0; count < 4; ++count)
{
vec.push_back(value);
}
}
The only optimization I would do is making sure that the capacity of the vector is sufficient before entering the loop. I would leave other optimizations to the compiler. My guess is, what you gain by omitting the inner loop, you lose by frequent modulo division.
You did not initialize i, and you are resetting fourth in every iteration. Also, with your for loop condition, I do not think it will do what you want.
I think this should work:
int fourth = 0;
for (int i = 2; i<=10;) {
fourth++;
fourth%=4;
vec.push_back(i);
if (fourth==0) {
i++;
}
}
I've been able to create a static array declaration and pass that array into the vector at initialization without issue. Pretty clean too:
const int initialValues[36] = {0,1,2...,35};
std::vector foo(initialValues);
Works with constants, but haven't tried it with non const arrays.