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

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.

Related

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.

Vector not dereferencable

After having looked at the comments I looked through the code and found an error.
It seems after some tinkering I got faced with this error:
Debug error: vector iterator is not dereferencable.
I'm 100% certain that it is in the vector inside assingthreads.
This is the newly added code that spawns the error:
void historical::writeData(std::vector<std::vector<std::wstring>> in, const string& symbol) {
std::cout << "Sending data to database connector" << std::endl;
std::vector<std::vector<std::wstring>> temp;
while (!in.empty()) {
for (int i = 0; i < 5; i++) {
temp.push_back(in.back());
in.pop_back();
}
assignthreads(temp, symbol);
temp.clear();
}
}
void historical::assignthreads(std::vector<std::vector<std::wstring>> partVec, const string& symbol) {
int i = 0;
std::thread threads[5];
std::vector<std::vector<std::wstring>>::iterator it;
for (it = partVec.end();
it != partVec.begin();
it--) {
std::shared_ptr<database_con> sh_ptr(new database_con);
threads[i] = std::thread(&database_con::start, sh_ptr, *it, symbol);
partVec.pop_back();
i++;
}
for (auto& th : threads) th.join();
}
Your first time through the for-loop, it = partVec.end().
By definition you cannot dereference the end of a vector but you call:
threads[i] = std::thread(&database_con::start, sh_ptr, *it, symbol);
The for loop you intended probably used reverse iterators, rbegin and rend like this:
for(auto it = rbegin(partVec); it != rend(partVec); ++it)
A couple additional notes:
Pass your vector by reference: void assignthreads(std::vector<std::vector<std::wstring>>& partVec, const string& symbol)
You need to validate that threads is the same size as partVec. So either do: vector<thread> threads(size(partVec)) or after threads is defined do: assert(size(threads) == size(partVec))
At least one issue with the for loop in assignthreads is that you attempt to dereference the end() of the vector;
for (it = partVec.end(); it != partVec.begin(); it--) {
// ...
threads[i] = std::thread(&database_con::start, sh_ptr, *it, symbol);
// ^^^^
}
And on the first iteration of the loop this is undefined; your debugger is just telling you that.
If you want to "reverse" through the loop, use the reverse_iterator of the container (available via rbegin() and rend())
for (it = partVec.rbegin(); it != partVec.rend(); ++it)
Side note it is generally not advised to modify the container whilst iterating through it (via partVec.pop_back();). Since you don't seem to do anything with what is removed from the vector, it may just as well be better to iterate over the contents, and then call std::vector<>::clear() to remove all the contents from the vector after the loop.

vector iterator incrementable when erasing element of vector in 2 for loops

I am currently programming a little game for the console with an 2D map. 2 Elements of my game are: destroying fields and an enemy, which spreads in a random direction (its getting bigger). These two "entities" are saved in a structure which contains two vectors (X and Y). I am now trying to erase an element of "_Enemy"(<-private instance of the structure in a class, same as "_DestroyedFields") if you destroy the field where the enemy is.
I tried a lot of different variations to do so and whats giving me the error least is this method (I already searched the internet for a while now an couldn't find a answer to my question):
for (std::vector<int>::iterator itEX = _Enemys.X.begin(), itEY = _Enemys.Y.begin();
itEX != _Enemys.X.end() && itEY != _Enemys.Y.end();
++itEX, ++itEY) {
for (std::vector<int>::iterator itX = _DestroyedFields.X.begin(),
itY = _DestroyedFields.Y.begin();
itX != _DestroyedFields.X.end() && itY != _DestroyedFields.Y.end();
++itX, ++itY) {
if (*itY == *itEY && *itX == *itEX){
itEY = _Enemys.Y.erase(itEY);
itEX = _Enemys.X.erase(itEX);
}
}
}
PS: sorry if my english isn't the best, im german ^^
PSS: if you wanna watch over my whole code, you can find it on Github: https://github.com/Aemmel/ConsoleGame1
After erasing using iterator it, you cannot use it further as it is invalidated. You should use a result of a call to erase which is new, valid iterator.
for( it = v.begin(); it != v.end();)
{
//...
if(...)
{
it = v.erase( it);
}
else
{
++it;
}
...
}
I fixed the bug with first: making a "simple structure"(struct Entity{int X; intY} and then std::vector [insert name here]) and then with adding an break; if the condition is true.
for (Uint itE = 0; itE < _Enemys.size(); ++itE){
for (Uint it = 0; it<_DestroyedFields.size(); ++it){
if (_Enemys.at(itE).Y == _DestroyedFields.at(it).Y
&& _Enemys.at(itE).X == _DestroyedFields.at(it).X){
_Enemys.erase(_Enemys.begin()+itE);
break;
}
}
}
With struct Position {int x; int y;}; and some utility operators,
you may do one of the following: (https://ideone.com/0aiih0)
void filter(std::vector<Position>& positions, const std::vector<Position>& destroyedFields)
{
for (std::vector<Position>::iterator it = positions.begin(); it != positions.end(); ) {
if (std::find(destroyedFields.begin(), destroyedFields.end(), *it) != destroyedFields.end()) {
it = positions.erase(it);
} else {
++it;
}
}
}
Or, if input are sorted, you may use a 'difference':
std::vector<Position> filter2(const std::vector<Position>& positions, const std::vector<Position>& destroyedFields)
{
std::vector<Position> res;
std::set_difference(positions.begin(), positions.end(),
destroyedFields.begin(), destroyedFields.end(),
std::back_inserter(res));
return res;
}

Vector iterator erase giving me a runtime error?

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.

How to remove odd positions from a list?

#include<iostream>
#include<list>
using namespace std;
void compute(int num)
{
list<int> L;
list<int>::iterator i;
list<int>::iterator i2;
int p;
cout<<"Enter the number of numbers\n";
cin>>p;
int a;
for(int k=1;k<=p;k++)
{
cin>>a;
L.push_back(k);
}
cout<<endl;
for(i=L.begin() ; i!=L.end() ; ++i)
{
cout<<*i<<endl;
}
long int k=1;
for(i=L.begin() ; i!=L.end() ; ++i )
{
if(k%2!=0) //This is where I try and delete values in odd positions
{
i2=L.erase(i);
}
k++;
}
for(i=L.begin() ; i!=L.end() ; ++i )
{
cout<<*i<<endl;
}
}
int main()
{
// int testcases, sailors;
//cin>>testcases;
//for(int i=1 ; i<=testcases ; i++)
{
// cin>>sailors;
}
//for(int i=1;i<=testcases;i++)
{
// int num;
//cin>>num;
//compute(num);
}
compute(0);
return 0;
}
I am trying to erase elements using L.erase() function in Lists. But I get an error saying
"Debug assertion failed! ......Expression:list iterator not incrementable"
but we CAN increment iterator right?
erase invalidates the iterator that was passed in as parameter - since the element at the position the iterator was pointing to was just erased! And on that same iterator, an increment is attempted in the next for loop in your code! That's why it fails.
However, erase it will return an iterator pointing to the new position, which we can use; a loop where you erase something from an STL container should therefore look something like the following; I show it with the type you use, list, but you could just as well use e.g. vector:
list<int> L;
// ...
list<int>::iterator it=L.begin();
while (it!=L.end())
{
if(eraseCondition)
{
it=L.erase(it);
}
else
{
++it;
}
}
Or, if possible, it's even better to use std::remove_if:
container.erase(std::remove_if(L.begin(), L.end(), predicate), L.end());
In your case that will be hard - if not impossible - to use since the predicate would need state information (the information whether the index is odd or even). So I'd recommend going with a loop structure as mentioned above; just keep in mind the remove_if for the general case of removing all elements where a certain predicate returns true!
Adding to what wOOte said, you may want to used a reverse iterator to get around the issue.
Technically not in this case.
When you use erase() you delete the node that was pointed to, so you actually invalidate the iterator you were on. So when you increment it it's undefined behavior.
It might be best to create a second list with just the iterators to the positions you'd like to delete, and you can cycle through those and call erase afterward. You wouldn't be erasing the iterators from the second list, so it'd work.
Something like this:
List<IteratorType> deleteList;
//Populate deleteList with every other element from original list.
for (List<IteratorType>::iterator iter = deleteList.begin();
iter !=deleteList.end; ++iter)
{
originalList.erase(*iter);
}
The iterator i is invalidated by the call to erase; however, in the next iteration of the for loop, you try to increment it - this is invalid.
Try
for(i=L.begin() ; i!=L.end() ; )
{
if(k%2!=0) //This is where I try and delete values in odd positions
{
i=L.erase(i);
} else {
++i;
}
k++;
}
instead - only increment the iterator if you don't erase (erase basically "advances" the iterator because it yields an iterator to the element following the one you erased).
You can actually exploit this behaviour of erase to write your function without requiring k:
i = L.begin();
while ( i != L.end() ) {
i = L.erase( i ); // Delete one
if ( i != L.end() ) { // Skip next, if there's an element
++i;
}
}
So you delete the first element, skip the second, delete the third, and so on.