unordered_set erase not working in C++ - c++

Consider the following situation
void first(){
unordered_set<int> validPorts;
int roundNum=0, preFunctionSize, postFunctionSize,j=0 ;
while(j <100){
if(some_condition_A){
validPorts.insert(some_int_value);
}
j++;
}
do{
preFunctionSize = validPorts.size();
second( validPorts, some_int_value );
postFunctionSize = validPorts.size();
}while(roundNum<12);
}
void second( unordered_set<int> & validPorts, int some_int_value ){
for (auto it = validPorts.begin(); it != validPorts.end();) {
if (it == validPorts.find(some_int_value)) {
validPorts.erase(it++); // <== CODE enters here, I checked
} else {
++it;
}
}
}
So I expect that the postFunctionSize should be less than the preFunctionSize since I know that it went till the erase function. But it looks like the erase function does not work since i get the same value for the two of them. I am not really sure whats happening here and what is causing it. Can you guys please help me out on what might be wrong with this?

Your code is pseudo of course in places but you need to do:
it = validPorts.erase( it );
in a loop where you are iterating through a collection erasing some of them.
However that is also not really what you want to do. You are trying to erase a value from your unordered_set so just do
validPorts.erase( some_int_value );
and no loop.

Related

How to remove elements from a vector that uses the vector size in the for loop

I have a game where I shoot bullets at an object and I delete the object that gets hit by the bullet and bullet that are off screen as well.
For example:
std::vector<object> object_list;
for(size_t i = 0; i < object_list.size(); i++)
{
if(object_list[i].hit())
{
object_list.erase(object_list.begin() + i);
}
else
object_list[i].draw();
}
The problem with this is that when i remove an object, the size of the vector decreases so when it check the conditions, it fails and i get an error such as " vector subscript out of range." I could just choose not to render the asteroid by rendering those that haven't been hit, but the problem with that is that the no. of objects increases when hit(splits up) so eventually the program is going to get slower. I've used a similar concept for the off screen bullets but I can't find a way around it. I'm looking for a solution to this or better way of removing elements.
Both object and bullet are classes.
You should split for loop in 2 parts:
remove all "hit" elements:
object_list.erase(std::remove_if(object_list.begin(),
object_list.end(), [](auto&& item) { return item.hit(); }),
object_list.end());
draw remaining:
std::for_each(object_list.begin(), object_list.end(), [](auto&& item) { item.draw(); });
It's safer and more readable.
Same idea as the other answers but this code is a little easier with iterators
for (auto i = object_list.begin(); i != object_list.end(); )
{
if (i->hit())
{
i = object_list.erase(i);
}
else
{
i->draw();
++i;
}
}
vector::erase returns an iterator to the next element, which you can use to continue the loop.
Functional approach using the range-v3 library (C++20)
[...] I'm looking for a solution to this or better way of removing elements.
Using the ranges::actions::remove_if action from the range-v3 library, you can use a functional programming style approach to mutate the object_list container in-place:
object_list |= ranges::actions::remove_if(
[](const auto& obj) { return obj.hit(); });
followed by subsequent ranges:for_each invocation to draw the object:
ranges::for_each(object_list, [](const auto& obj){ obj.draw(); });
DEMO.
You could do something like this:
for (size_t i = 0; i < object_list.size(); )
{
if (object_list[i].hit())
object_list.erase(object_list.begin() + i)
else
{
object_list[i].draw()
++i;
}
}
Let us say you are at i=5 and that object has been hit, after deleting that element, the obj at i=6 is shifted to i=5, and you haven't checked it, so just add i--; after your erase statement.
Another way to do it would be -
for(size_t i = 0; i < object_list.size();)
{
if(object_list[i].hit())
{
object_list.erase(object_list.begin() + i);
}
else
{
object_list[i].draw();
i++;
}
}
Also, it could possibly be faster to just remove the object from the vector where you execute the code that marks the object as hit, that way you just need to draw all the objects which are left out in the list. Some more background into how you are doing all this would be helpful to decide something specific which would be better :)
The shown code does not fail or give a vector subscript out of range - it just does not consider every object, as it skips over the element after the removed one.
For very short and concise solutions employing concepts from C++11 and later, see the answer by Equod or the one by dfri
For better understanding the issue, and/or if you have to stick to for loops with indices, you basically have two options:
Iterate over the vector in reverse direction (i.e. start at the last element), then items after the current one being shifted is not a problem;
for (int i=object_list.size()-1; i>=0; --i)
{
if (object_list[i].hit())
{
object_list.erase(object_list.begin() + i)
}
else
{
object_list[i].draw()
}
}
Or, if the order is important (as I could imagine with items to draw), and you have to iterate from front to back, then only increase the counter i if you have not erased the current element:
for (int i=0; i<object_list.size(); /* No increase here... */ )
{
if (object_list[i].hit())
{
object_list.erase(object_list.begin() + i);
}
else
{
object_list[i].draw();
++i; // ...just here if we didn't remove the element
}
}
I suspect that std::vector is not the container you want (but, of course, I don't know the entire code). Each call to erase implies reallocation of the right-part of the vector (and then copies of you objects), it could be very costly. And your actual problem is the symptom of a design problem.
From what I see, std::list is probably better:
std::list<object> objects;
// ...
for(std::list<object>::iterator it = objects.begin(); it != objects.end();)
{
if(it->hit())
objects.erase(it++); // No object copied
else
{
it->draw();
++it;
}
}

My iterators are not working the way they are supposed to be working

So this is my code for selection sort and for some reason the part where I swap the two elements it doesn't work and gives all sorts of weird outputs.
vector<int> vect{45,32,12,1,67,34,2,15,33,40};
for(auto i=vect.begin();i<vect.end()-1;i++){
auto min=i;
for(auto j=i+1;j<vect.end();j++)
{
if(*min>*j)
{
min=j;
}
}
*i=*i+*min;
*min=*i-*min;
*i=*i-*min;
}
for(int x:vect)
{
cout<<x<<" ";
}
But when I use a different way of swapping the output comes out correct.
int temp=*min;
*min=*i;
*i=temp;
instead of:-
*i=*i+*min;
*min=*i-*min;
*i=*i-*min;
Please help me find out where it went wrong.
Welcome to C++!
Your main problem here is that there are case when iterator i points the same object as iterator min.
What you will really get is
*i=*i+*i;
*i=*i-*i;
*i=*i-*i;
Hence you will get a zero result!
In order to fix that you must not swap when iterators are equal.
vector<int> vect{45,32,12,1,67,34,2,15,33,40};
for(auto i=vect.begin();i<vect.end()-1;i++){
auto min=i;
for(auto j=i+1;j<vect.end();j++)
{
if(*min>*j)
{
min=j;
}
}
if (i==min) continue; // ADD THIS
*i=*i+*min;
*min=*i-*min;
*i=*i-*min;
}
for(int x:vect)
{
cout<<x<<" ";
}
Best Regards!
You always need a temp variable to swap two elements. It's exactly like you want to swap two cups, you'd need a third.

iterate through vector with for loop in c++

I am reading a tutorial about joystick input handling with SDL and I am struggling with a part of the code.
In .h file I got:
std::vector<std::pair<Vector2D*, Vector2D*> > m_joystickValues;
and in .cpp file I got:
m_joystickValues.push_back(std::make_pair(new Vector2D(0,0),new Vector2D(0,0)));
In this case I have one joystick, if there is many joysticks there will more push_backs, I want to access the adresses in "m_joystickValues" so I can delete them in a clean function.
Anyone has an idea how I can do this with a for loop. Thanks
For example you can use the range-based for statement
for ( auto &p : m_joystickValues )
{
delete p.first;
delete p.second;
}
The same can be done using the ordinary for statement
for ( size_t i = 0; i < m_joystickValues.size(); i++ )
{
delete m_joystickValues[i].first;
delete m_joystickValues[i].second;
}
Or you can use standard algorithm std::for_each with an appropriate lambda-expression. It is similar to using a for statement with iterators.
for(int i = 0; i < m_joystickValues.size(); i++)
{
m_joystickValues[i] //do something with this
}
Is this what you are looking for? Also, you could use the at function, since it is more safe.
for(auto& i : m_joystickValues)
{
delete i.second;
delete i.first; // or do whatever
}
At end of the loop you can erase the entire vector
m_joystickValues.erase(m_joystickValues.begin(), m_joystickValues.end());

Vector iterator not incremental .erase()

I am trying to delete any element of this vector that collides with player. However when I try to remove the element from the vector the program crashes and I get the error; "vector iterator not incremental".
for (std::vector<Coin>::iterator i=CoinSet.begin(); i!=CoinSet.end(); i++)
{
if (i->PlayerClear(player.collider()) == true)
{
score++;
cout<<score<<endl;
CoinSet.erase(i);
}
}
This code works perfectly well until "CoinSet.erase(i)", I tried using "CoinSet.clear()" at various points, but to no avail. Any help on this would be great, thanks in advance!
This has been discussed to death. You mustn't operate on an invalid iterator. You want something like this:
for (auto it = CoinSet.begin(); it != CoinSet.end(); /* no increment here! */ )
{
if (/* ... */)
{
// ...
CoinSet.erase(it++);
}
else
{
++it;
}
}
I don't like putting ++-statements inside the argument. Therefore erase() returns an iterator that points to the next element, so one could replace the erase line with:
it = CoinSet.erase(it); // iterator is replaced with valid one

Trouble removing elements from C++ vector

I'm trying to remove 'dead' bullets from my vector of bullets. Every frame, I'm calling the Bullet::update() function which looks like this:
void Bullet::update()
{
for(int i = 0; i != mAmmo.size(); i++)
{
if(mAmmo[i].sprite.getPosition().x > 700)
mAmmo[i].mAlive = false;
if(mAmmo[i].mAlive == false)
{
// I get a Debug Assertion Failed at runtime from this piece of code
mAmmo.erase(mAmmo.begin()+i);
}
if(mAmmo[i].mAlive == true)
{
mAmmo[i].sprite.move(mMovement);
}
}
}
Am I doing this completely incorrectly? This is the first time I've really used vectors more than just following through a tutorial. If I need to post any more code, just tell me. I've been working on this for the past few hours, so I'm a wee bit desperate to get this to work.
Thanks in advance!
You're easily walking into undefined behavior as soon as the ith element is the last element in your list. Use iterators, and pay special attention to the return value of erase(), as it automatically advances the iterator for you so your loop doesn't have to.
void Bullet::update()
{
for (auto it = mAmmo.begin(); it != mAmmo.end();)
{
if(it->sprite.getPosition().x > 700)
it->mAlive = false;
if (!it->mAlive)
{
// erase and get next iterator
it = mAmmo.erase(it);
}
else
{ // move and increment
it->sprite.move(mMovement);
++it;
}
}
}