incompatible vector iterator - c++

I'm getting a "incompatible vector iterator" error to what i believe is a invalid iterator
void Bomb::CreateExplosion(Game_Manager* EGame_Manager)
{
for(irr::f32 iteration = 0; iteration < BlastRadius; iteration++) //up direction blast
{
***//PROGRAM CRASHES AT THIS LINE-->*** for(EGame_Manager->getEntityManager()->GetEntityIterator() = EGame_Manager->getEntityManager()->GetEntityList().begin(); EGame_Manager->getEntityManager()->GetEntityIterator() != EGame_Manager->getEntityManager()->GetEntityList().end(); ++EGame_Manager->getEntityManager()->GetEntityIterator())
{
if(CheckForCollision(UpExplosion->getTransformedBoundingBox(), (*EGame_Manager->getEntityManager()->GetEntityIterator())->GetEntityNode()->getTransformedBoundingBox()) == true)//check for collision against the unbreakable blocks (entity.type equals 0)
{
if((*EGame_Manager->getEntityManager()->GetEntityIterator())->GetType() == unbreakableblock)
{
break;
}
else if((*EGame_Manager->getEntityManager()->GetEntityIterator())->GetType() == gameplayer)
{
(*EGame_Manager->getEntityManager()->GetEntityIterator())->SetLives(this->GetLives() -1);
break;
}
else if((*EGame_Manager->getEntityManager()->GetEntityIterator())->GetType() == gameitem)
{
break;
}
}
else
{
UpExplosion->setScale(irr::core::vector3df(1,1,iteration)); //standard width of UpExplosion, iterated height of the UpExplosion
}
}
}
CreateExplosion is called by Bomb::UpdateEntity() which is called by EntityManager::UpdateList() which then loops through the vector<*Entity> List calling each Entity's respective Update function.
This function adds the Entities to the vector I'm not sure if it causes the problem
EntityManager::AddEntity(Entity* addtoList)
{
List.push_back(addtolist);
addtolist->GetEntityNode()->setID(List.size());
EntityIterator = List.begin();
}
Also the instance of the Bomb class that calls these functions is declared in the Player class if that helps with anything. And I can post more code if needed.

Related

Collision when in container is more than 1 element works unproperly

I am doing a Space Invaders game for a project in SFML, and I have had problem, because I check the collision of the Bullet with the Enemy and it works as it should, until there is one Bullet type object inside the container, when there are already two or more and a collision occurs, I am getting the error "Unhandled Exception at 0x00007FFF7BA9DD7E (ucrtbase.dll) in SI.exe: Fatal Exit Request.". I suspect the problem is with the iterator here as the amount of objects in the container is variable.
void Bullet::hit(vector<Enemy>& enemies,vector<Pixel>& oneShield, vector<Bullet>& bullets, int &killedEnemies, int shotsFired) {
for (auto& enemy : enemies) {
if (enemy.shape.getGlobalBounds().intersects(this->shape.getGlobalBounds())) {
for (auto i = enemies.begin(); i < enemies.end(); i++) {
if (i->ID == enemy.ID) {
enemies.erase(i);
break;
}
}
killedEnemies = killedEnemies + 1;
//Problem with this loop below
for (auto j = bullets.begin(); j < bullets.end(); j++) {
if (j->ID == this->ID) {
bullets.erase(j);
break;
}
}
}
}

How to update values in C++ std::pair<int, int>

I have this function that returns the location of a robot (which is just a [row][col] pair of indices from a matrix):
std::pair<int, int> World::getRobotLocation(char robot_name){
auto const & location = robots.find(robot_name);
if (location == robots.end()) {
std::cout << "Robot " << robot_name << " does not exist." << std::endl;
}
return location->second;
}
Below, I am trying to implement the move() function, which takes in the robot name, location and which direction to move and updates the position accordingly:
std::string move(char robot, char direction) {
// Get robot and its location
std::pair<int, int> robot_location = std::pair<int, int> World::getRobotLocation(robot);
// Get direction to move from user
// if L, map_[row+1][col]
// if D, map_[row][col+1]
// if R, map_[row-1][col]
// if U, map_[row][col+1]
// According to user input, update the robot's location
if (direction == 'L') {
robot_location = robot_location[+1][]
}
else if (direction == 'D') {
robot_location = robot_location[][-1]
}
else if (direction == 'R') {
robot_location = robot_location[-1][]
}
else {
robot_location = robot_location[][+1]
}
}
In my variable robot_location, I am saving the location of that particular robot. How can I access the values of this std::pair<int, int> to be able to update them?
Your first function has a bug. It reports when a robot is not found, but still dereferences the end iterator, which causes undefined behavior. Instead, you should return a pointer, which is conditionally null:
// Returns null if the robot is not found:
std::pair<int, int>*
World::getRobotLocation(char robot_name){
auto const location = robots.find(robot_name);
if (location == robots.end()) {
return nullptr;
}
return &location->second;
}
And in your other function, you check to see, if the pointer is not null, you update the value:
// Returns true if move happens,
// false otherwise.
bool
move(char robot, char direction) {
auto const robot_location = World::getRobotLocation(robot);
if (!robot_location) return false;
switch (direction) {
case 'L': {
++robot_location->first;
} break;
case 'D': {
--robot_location->second;
} break;
case 'R': {
--robot_location->first;
} break;
default: {
++robot_location->second;
} break;
}
return true;
}
I think you want something like this:
if (direction == 'L') {
robot_location.first += 1;
}
else if (direction == 'D') {
robot_location.second -= 1;
}
// ...etc (you get the idea)
first and second are the names of the two elements in a std::pair (that's also why the return value of robots.find(...) dereferences to something that has first and second - that's a std::pair of the key and value types of the map).
Bear in mind that getRobotLocation, as it's currently written, will return a copy of the std::pair of coordinates, not a reference to the original coordinates inside the map. Therefore, just updating that std::pair won't be enough on its own. You'll need to either save the value back into the robots map, or change what getRobotLocation returns (see #Goswin and #Ted's comments).

How to delete elements from two lists upon contact?

I'm having an incredibly difficult time programming Space Invaders for a class. I am supposed to use a list to store my "missiles" and a list to store my "aliens" as well. I press space bar to load in a new alien, and when the two contact, I am attempting to delete both of them, and I can't even get past deleting the "alien". I get a variety of bugs when more than one missile is fired, and the missiles work fine if this function is commented out. I am forced to pass a list of missiles into another class that already contains a list of aliens and delete both.
Here is the offending code:
bool AlienMgr::checkHit(PlayerMgr& playerMgr)
{
bool hit = false; // If the player hits an alien, switches to true and is returned.
list<Missile*>::iterator missileIter;
list<Missile*> missileList = playerMgr.getMissiles();
int missileCount;
FloatRect missileBounds;
FloatRect alienBounds;
iter = myAliens.begin();
while (!myAliens.empty() && iter != myAliens.end())
{
alienBounds = (*iter)->getGlobalBounds();
if (!missileList.empty() && !hit)
{
for (missileIter = missileList.begin(); missileIter != missileList.end() && !hit; missileIter++)
{
missileBounds = (*missileIter)->getMissileBounds();
if (alienBounds.intersects(missileBounds))
{
delete (*iter);
iter = myAliens.erase(iter);
cout << "HIT" << endl;
}
else
{
iter++;
}
}
}
else
{
iter++;
}
}
return hit;
}
You have several problems in your code. I've tried to clean them up. Also, I hope you can use c++ 11.
bool AlienMgr::checkHit(PlayerMgr& playerMgr)
{
bool hit = false; // If the player hits an alien, switches to true and is returned.
list<Missile*> missileList = playerMgr.getMissiles();
int missileCount;
FloatRect missileBounds;
FloatRect alienBounds;
// iter == myAliens.end() if it's empty
for (auto iter = myAliens.begin(); iter != myAliens.end();)
{
bool hitDetected = false;
alienBounds = (*iter)->getGlobalBounds();
// remove all missiles intersecting current alien and set flag
missileList.remove_if([&](Missile* missile)
{
if (!alienBounds.intersects(missile->getMissileBounds()))
return false;
hitDetected = true;
delete missile;
return true;
});
if (hitDetected)
{
hit = true;
delete (*iter);
iter = myAliens.erase(iter);
cout << "HIT" << endl;
else
{
iter++;
}
}
return hit;
}
However, there are more critical problems. Your code is too c++98'ish.
I would advise several improvements:
Use std::vector instead of std::list (it's really hard to find case when list will be faster)
Use smart pointers instead of manual memory management (code would be much simple and easier to understand)

"List iterators incompatible" while running

void GameLogic::isHit(int mousePressX, int mousePressY)
{
for each(BallObject* ball in ballList) {
for (it = ballList.begin(); it != ballList.end();)
{
bool isHit = ball->EvaluateHit(mousePressX, mousePressY);
if (isHit == true)
{
mScore++;
ballList.remove(ball);
}
else
{
++it;
}
}
}
I am trying to remove ball from "ballList" while playing game via click on surface(ball should dissapear). Program is running correctly until click. When I click, it gives an error from the title. How does it right?
void GameLogic::isHit(int mousePressX, int mousePressY)
{
// iterate all the balls in the list...
for (it = ballList.begin(); it != ballList.end();)
{
bool isHit = (*it)->EvaluateHit(mousePressX, mousePressY);
if (isHit == true)
{
mScore++;
// This invalidates iterators, and is linear in complexity
// (it iterates the list too, but you're already doing that)
// ballList.remove(ball);
// erase the ball at this iteration, save off the result
// so you can continue iterating
it = ballList.erase(it);
}
else
{
// if the ball wasn't hit, increment the iterator normally
++it;
}
}
}

Memory in use issue using marmalade SDK

I have a bullet class. and I try to instantiate it by the following code:
I always get an assertion that there is a memory that is in use.. why?
In another class called ship:
if (g_Input.isKeyDown(s3eKeySpace))// && Canfire)
{
Bullet *bullet = new Bullet();
bullet->Init(SHIP_BULLET);
bullet->setPosition(Position.x, Position.y - 20);
Bullets->push_back(bullet);
Canfire = false;
}
This is called each frame which causes memory still in usage:
for (list<Bullet*>::iterator it = Bullets->begin(); it != Bullets->end();)
{
(*it)->Update(dt);
if ((*it)->IsDestroyed)
{
Canfire = true;
it = Bullets->erase(it);
}
else
{
it++;
Canfire = false;
}
}
the destructor of the Ship class
Ship::~Ship()
{
for (std::list<Bullet*>::iterator it = Bullets->begin(); it != Bullets->end(); ++it)
delete *it;
delete Bullets;
}
class Bullet
{
public:
Bullet();
~Bullet();
public:
void Init(BulletTypes bulletType);
void Update(float dt);
void Render();
CIw2DImage* Image; // curr image
}
void Bullet::Init(BulletTypes bulletType)
{
BulletType = bulletType;
if (BulletType == SHIP_BULLET)
{
Image = Iw2DCreateImage("textures/ship_bullet.png");
if (Image == nullptr)
return;
}
}
Bullet::~Bullet()
{
delete Image;
}
Executing this code causes the leak:
for (list<Bullet*>::iterator it = Bullets->begin(); it != Bullets->end();)
{
(*it)->Update(dt);
if ((*it)->IsDestroyed)
{
Canfire = true;
it = Bullets->erase(it);
}
else
{
it++;
Canfire = false;
}
}
What is going on is basically you removing a dynamically allocated element from a container, losing any reference to it thus you cannot free its memory anymore. Calling Ship destructor only frees the elements that are currently in the list, excluding the ones removed in the iteration, obviously.
I suggest this as a fix:
for (list<Bullet*>::iterator it = Bullets->begin(); it != Bullets->end();)
{
(*it)->Update(dt);
if ((*it)->IsDestroyed)
{
Canfire = true;
delete *it; // it now points to invalid address
it = Bullets->erase(it);
}
else
{
it++;
Canfire = false;
}
}
Another option would be to store all removed bullets in some other container in class Ship in case that a Bullet can be referenced after it was destroyed. Problem with this idea is that you have alot of destroyed bullets taking up memory and have to come up with a solution on how to remove them once they really prove useless.
If you get stuck with that, using std::shared_ptrs instead of raw pointers in the list could solve your issue (for slight performance penalty).