Vector iterator erase giving me a runtime error? - c++

So I got a methode inside my class, and what this class is supposed to do is, check if the vector i have in the .h file have values bewtween double low & double high and then delete those and at last return how many "spaces" got removed
So I tried a few things and i always get runtime errors, it seems to be in the for loop, but i can´t figure out why.
Here is what i tried,
First I tried to just do it the way I felt like it would work:
int datastorage::eraseDataPointsBetween(double low,double high)
{
int antal = 0;
for (vector<double>::iterator i = data_.begin(); i !=data_.end();i++)
{
if (*i >=low && *i <=high)
{
data_.erase(i);
antal++;
}
}
return antal;
}
But then I tried to do some debugging and I could see that it actually doesn´t make sence to have it like that as when something gets deleted it still gets incremented(so if we delete "space 2" it would actually check space 4 next time(as spot 3 get to be spot 2 after erase)))
So I tried to change it to this
int datastorage::eraseDataPointsBetween(double low,double high)
{
int antal = 0;
for (vector<double>::iterator i = data_.begin(); i !=data_.end();)
{
if (*i >=low && *i <=high)
{
data_.erase(i);
antal++;
}
else
i++;
}
return antal;
}
Where it only increment the i whenever i do not remove a space(so if I delete "space 2", it will check the new "space 2" next run)
This also gives me a syntax error expression: vector iterators incompatible
Hope you can help because I'm pretty lost

vector::erase invalidates iterator so you cannot use it after call to erase.
You should erase from a vector this way:
int datastorage::eraseDataPointsBetween( double low, double high) {
int antal = 0;
for( vector<double>::iterator i = data_.begin(); i !=data_.end())
{
if( (*i >= low) && (*i <= high))
{
i = data_.erase( i); // new (valid) iterator is returned
++antal;
}
else
{
++i;
}
return antal;
}

You should use the remove_if() and erase. The reason why this is somewhat more stable than writing your own loops is simple -- you can't get into trouble using invalid iterators.
#include <algorithm>
#include <vector>
struct IsBetween
{
double low, high;
IsBetween(double l, double h) : low(l), high(h) {}
bool operator()(double d) const { return d >= low && d <= high; }
};
void datastorage::eraseDataPointsBetween(double low,double high)
{
std::vector<double>::iterator it = std::remove_if(data.begin(), data.end(), IsBetween(low, high));
data.erase(it, data.end());
}
There are no loops, and note the use of remove_if() with a function object IsBetween.
The bottom line is that you should minimize the attempt to write loops that erase items in a container while you're looping over the container. There is remove_if(), remove(), partition(), etc. that moves the data you want to focus on to one end of the container.
As much as you'll see answers that erase an iterator while looping, and it seems safe, how many will remember the rules of what is returned, or rather simply, write the loop incorrectly? (even experienced C++ programmers could have written the loop incorrectly on the first cut). So use the algorithms to do this work for you.
For remove_if(), the "bad" data is moved to the end, where you can now easily erase them.

Related

Finding most common element in a list (C++ STL)?

I have a program where I have to find the most common element in a list of integers. I do this with the program below, but the problem is, I suspect that the erase function messes up with the iterator incrementation in the countRepetition() function. My question is how can I fix the problem or if this is not the issue what is it?
Thanks in advance.
You have a couple issues. First, as you suspected, was the incorrect use of erase. When you erase an iterator it invalidates the iterator. Any use of the iterator afterwards is undefined behavior. Since erase returns the next valid iterator what you can do is restructure the loop like
for (START = l.begin(); START != l.end();) { // do not increment here
if (*START) {
counter++;
START = l.erase(START); // erase and get next
}
else
{
++START; // go to next
}
}
So now at least you loop through the list. Unfortunately you will still have an invalid iterator in main. You pass START from main to countRepetition and when that iterator is erased from the list you then have an invalid iterator. What you need to do is get a new begin iterator from the list each iteration since you are always erasing the first element. That would make your for loop look like
for (START = l.begin(); START != l.end(); START = l.begin()) {
m.push_back(countRepetition(START));
}
Another issue is you just check if the character is not 0. If you are counting repetitions you need to make sure you are checking that the iterator is the same character. I'll leave that for you to implement.
I would also like to point out there is an easier way to do all of this. A std::map lets you build a histogram very easily. Combine that with std::max_element and you could write your entire program as
int main()
{
std::map<char, int> histogram;
while ('0' != (number = getchar()))
++histogram[number]; // add to map, increment count of occurances
auto most_frequent = *std::max_element(histogram.begin(),
histogram.end(),
[](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; }).first;
std::cout << most_frequent;
return 0;
}
Your problem is that you use global variables everywhere.
The global START is changed in two loops, so you only access the first loop once, then it is changed again in the second function and you don't execute the first loop a second time.
Why do you use the global variables? You should not use them but use local variables.
This is probably what you are looking for:
#include <iostream>
#include <list>
#include <vector>
#include <map>
using namespace std;
list <char> l;
map<char, int> ans;
int main()
{
char c;
do{
c = getchar();
l.push_back(c);
}while(c != '0');
for(auto chr: l){
ans[chr]++;
}
char ch;
int mx = 0;
for(auto k: ans){
if(k.second > mx)
{
ch = k.first;
mx = k.second;
}
}
cout<<ch<<" : "<<mx;
}

using a std::vector<Particle> particles; function .at() not working with iterator it as parameter inside a for loop

class Particles {
constexpr static int particleNum = 25;
constexpr static double gravity = 1.1;
std::vector<Particle> particles;
std::vector<Particle>::iterator it = particles.begin();
};
I am trying to create the 25 particles that are specified above and for that I'm using the it iterator in the for loop which works fine but when the particles.at(it) is used the console outputs an error code that says:
error: no matching function for call to
'std::vector::at(std::vector::iterator&)'
if (!particles.at(it).life){
I have tried using a simple integer for this task but then I have the particles.erase(it) not working as it needs an it_&; just take a look:
Particles::Particles(sf::RenderWindow& renderWindow, int x, int y) {
for(unsigned int i = 0; i <= particleNum; i++){
particles.push_back(Particle(x, y));
}
do{
for(; it <= particles.end();){
if (!particles.at(it).life){
it = particles.erase(it);
}else{
particles.at(it).update();
it++;
}
renderWindow.draw(particles.at(it).particleShape);
}
}while(!particles.empty());
// to change later for different effects:
}
Without modifying the code you have created beyond your context, thedo while loop can be done like so:
unsigned int ctr = 0;
do{
for(; it != particles.end(); ++it){
++ctr;
if (!particles.at(ctr).life){
it = particles.erase(it); //keep in mind erase invalidates all iterators from [it:end)
}else{
particles.at(ctr).update();
it++;
}
}
}while(!particles.empty());
Additionally, there's a few other ways you could achieve the desired effect. For example, using just the counter instead, and using particles.begin() + ctr to specify the offset; with proper checks of course that it isn't beyond particles.end(). Another option instead of using at, is to access the iterator if not end as well. For example:
do{
for(; it != particles.end(); ++it){
if (!it->life){
particles.erase(it); //erase this item here
it = particles.begin(); //reinitialize the iterator to beginning to continue searching
}
else{
it->update();
it++;
}
}
}while(!particles.empty());
Otherwise, yet another possibility is to call particles.back().update() as required and use pop_back after the update call, or once checking to see if you need to remove it is completed.
There are probably other more/less obvious ways to do the same thing as well.
You are trying to pass an iterator to the at method, but that method has a parameter of type size_type, not std::vector::iterator&. You need to call the method with a simple index, not an iterator.

Moving through list starting at both ends and stopping at middle using iterators

I'm trying to make a while loop for some code that has two iterators, one that starts at the beginning of the list, and is incremented and another that started at the end and is decremented, wanting them to stop once the middle of the list is reached and the whole list has been covered. When doing a similar thing with vector iterators I was able to just do while (limit > first), but this doesn't work and gives a compiler error when done with list iterators. I'm working on a book problem that has a task requirement of not allocating any new memory in the code aside from the two given iterators and am having trouble figuring out how to move through the elements of the list properly.
Reverse iterators dereference to the prior element than the one they internally refer to (the "base"). (See this image for a visual explanation.)
What this means is that if you have:
auto forward = a_list.begin();
auto backward = a_list.rbegin();
And you increment forward and backward alternately, there will be a time when forward == backward.base(). You must test this after incrementing each iterator, not both otherwise they could cross each other before you test them.
You can use std::list::size:
#include <list>
using namespace std;
void handle(int v) { cout << v << endl; }
void main() {
list<int> l = { 1,2,3,4,5,6,7,8,9 };
auto f = l.cbegin();
auto r = l.crbegin();
const int stepsCount = l.size() / 2;
for (int i = 0; i < stepsCount; ++i) {
handle(*f); handle(*r);
f++; r++;
}
if (l.size() % 2) handle(*r);
}

C++, Visual Studio 2015, Vector iterator not dereferencable

Ok, so i managed to write a method for deleting missles in my game, but i am constantly getting this error and i don't know why. Any ideas how to deal with the problem? Besides, i'd like to get rid of this i iterator, but then i don't know how to use properly delete and erase for the missle.
{
int i = 0;
for (auto it = missle_vector.begin(); it != missle_vector.end(); ++it) {
score += missle_vector[i]->collision(i, missle_vector, enemy_vector, obstacle_vector, 1);
displayMissle(**it);
(*it)->moove(50, 0);
i++;
}
} //this is how i use it
int Missle::collision(unsigned int i, vector <Missle*> &missle_vector, vector <Enemy*> &enemy_vector,
vector <Obstacle*> &obstacle_vector, bool G)
{
int hit=0;
for (auto it=enemy_vector.begin(); it!=enemy_vector.end(); )
{
double x, y;
x=(*it)->getX()-getX();
y=(*it)->getY()-getY();
if (x<64 && x>-151 && y<14 && y>-103)
{
delete missle_vector[i];
missle_vector.erase(missle_vector.begin() + i);
delete *it;
enemy_vector.erase(it);
hit++;
}
else
++it;
}
if(G){
for (auto it=obstacle_vector.begin(); it!=obstacle_vector.end(); ++it)
{
double x, y;
x=(*it)->getX()-getX();
y=(*it)->getY()-getY();
if (x<64 && x>-61 && y<14 && y>-61)
{
delete missle_vector[i];
missle_vector.erase(missle_vector.begin()+i);
}
}
}
if (getX()>1920)
{
delete missle_vector[i];
missle_vector.erase(missle_vector.begin()+i);
}
return hit;
} //method itself
This is an assertion:
Vector iterator not dereferencable
and it means you are derefencing and iterator which for example is end iterator. For example this short example will generate this assertion:
std::vector<int> v;
*v.end();
this assertion should appear at runtime during debugging and will allow you to find exact place where problem exissts. In Visual Studio you can use debugger to lookup local variables, call stack.
[edit]
one place where you can get this assertion in your code is here:
enemy_vector.erase(it);
this should be:
it = enemy_vector.erase(it);
otherwise in next iteration your it will be invalid and *it will result in Vector iterator not dereferencable. Even it!=enemy_vector.end() should be Undefined Behaviour.

Loop over ALL the values

This might be an odd question, but how does one nicely loop over ALL values of a type. In particular the standard integral types such as unsigned short. A normal for loop construct presents a difficulty: what condition to use to exit the loop - because all values are valid.
Of course, there are several ways to get the job done. Exit on the last value then handle that after the loop. Use a bigger int to count. The question is, is there a more elegant way?
I worried about this very same issue once, and this is the best I could think of:
unsigned char c = 0;
do
{
printf("%d ", (int)c); //or whatever
} while (++c != 0);
One of the very few cases where I find the do..while syntax useful.
Note that technically it is only valid for unsigned types, as I am relying on the wrapping of values.
#include <limits>
int i = std::numeric_limits<int>::min();
do {
...
if(i == std::numeric_limits<int>::max())
break;
i++;
} while(true);
This is in contrast to a for() statement which translates to:
#include <limits>
int i = std::numeric_limits<int>::min();
while(true) {
if(i == std::numeric_limits<int>::max())
break;
...
i++;
};
If you want a pretty solution you can do this:
for(auto x : everyvalue<short>()) {
std::cout << x << '\n';
}
Where everyvalue is:
#include <limits>
template<typename T>
struct everyvalue {
struct iter {
T x;
bool flag;
inline iter operator++() {
if(x == std::numeric_limits<T>::max())
flag = true;
else
++x;
return *this;
}
inline T operator*() { return x;}
inline bool operator!=(iter& i) {return flag != i.flag;}
// note: missing some iterator requirements, still should work
};
inline iter begin() { return iter{std::numeric_limits<T>::min(),0}; }
inline iter end() { return iter{std::numeric_limits<T>::max(),1}; }
};
Otherwise a simple break would be preferred.
You can combine the value by which you increment with a flag to say you've reached the max so you don't increment past it:
for ( char i ( std::numeric_limits<char>::min() ), j ( 1 );
i != std::numeric_limits<char>::max() || j--;
i += j )
std::cout << ( int ) i << '\n';
but only elegant as in 'sophisticated' rather than 'clean simple lines'.
Look up the minimum and maximum values?
You can just use a larger type:
unsigned long i;
for (i = std::numeric_limits<unsigned short>::min();
i <= std::numeric_limits<unsigned short>::max();
i++)
I recently asked the same question about bools: How to write a `for` loop over bool values (false and true). You may look for the answers there. I then realized that since a for-loop iterating over all possible values would need to evaluate the condition one more time, you need an extra value (in any form - a bigger type, a second variable, etc) to properly distinguish all cases. And, a do-while loop works for this case because it needs exactly as many comparisons as there are distinct values.