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).
Related
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)
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;
}
}
}
I've this piece of code, which is called by a timer Update mechanism.
However, I notice, that the memory size of the application, while running, continuously increases by 4, indicating that there might be a rogue pointer, or some other issue.
void RtdbConnection::getItemList()
{
std::vector<CString> tagList = mItemList->getItems();
//CString str(_T("STD-DOL1"));
PwItemList* pil = mPwSrv->GetItemList();
CPwItem pw ;
for(auto it = tagList.begin(); it != tagList.end(); ++it)
{
pw = mPwSrv->GetItem(*it);
pil->AddItem(&(PwItem)pw);
}
pil->AddInfo(DB_DESC); //Description
pil->AddInfo(DB_QALRM); // Alarm Status
pil->AddInfo(DB_QUNAK); //UNACK status
pil->AddInfo(DB_AL_PRI); // Priority of the alarm tag
pil->ExecuteQuery();
int i = 0;
for (auto it = tagList.begin(); i < pil->GetInfoRetrievedCount() && it != tagList.end(); i+=4, it++)
{
//item = {0};
CString str(*it);
PwInfo info = pil->GetInfo(i);
CString p(info.szValue().c_str());
bool isAlarm = pil->GetInfo(i+1).bValue();
bool isAck = pil->GetInfo(i+2).bValue();
int priority = pil->GetInfo(i+3).iValue();
item = ItemInfo(str, p, isAlarm, isAck, priority);
//int r = sizeof(item);
mItemList->setInfo(str, item); // Set the details for the item of the List
}
delete pil;
pil = NULL;
}
I cannot seem to find a memory block requiring de-allocation here. Nor is there any allocation of memory when I step inside the following function :
mItemList->setInfo(str, item);
which is defined as :
void ItemList::setInfo(CString tagname, ItemInfo info)
{
int flag = 0;
COLORREF tempColour;
std::map<CString, ItemInfo>::iterator tempIterator;
if ( (tempIterator = mAlarmListMap.find(tagname)) !=mAlarmListMap.end() )
{
//remove the current iteminfo and insert new one
if(mAlarmListMap[tagname].getPriority() != info.getPriority() && (mAlarmListMap[tagname].getPriority()!=0))
{
mAlarmListMap[tagname].updatePriority(info.getPriority());
mAlarmListMap[tagname].mPrioChanged = TRUE;
}
else
{
mAlarmListMap[tagname].mPrioChanged = FALSE;
((mAlarmListMap[tagname].getPrevPriority() != 0)?(mAlarmListMap[tagname].ResetPrevPriority()):TRUE);
mAlarmListMap[tagname].setPriority(info.getPriority());
}
mAlarmListMap[tagname].setDescription(info.getDescription());
mAlarmListMap[tagname].setAlarm(info.getAlarmStat());
mAlarmListMap[tagname].setAlarmAck(info.getAckStat());
tempColour = mColourLogic->setUpdatedColour(mAlarmListMap[tagname].getAlarmStat(), mAlarmListMap[tagname].getAckStat(), flag);
mAlarmListMap[tagname].setColour(tempColour);
if(!(info.getAlarmStat() || info.getAckStat()))
{
flag = 1;
mAlarmListMap[tagname].mIsRTN = true;
mAlarmListMap[tagname].setDisplayCondition(false);
}
else
{
mAlarmListMap[tagname].setDisplayCondition(true);
}
//((mAlarmListMap[tagname].mIsRTN == true)?
}
else
{
tempIterator = mAlarmListMap.begin();
tempColour = mColourLogic->fillColourFirst(info.getAlarmStat(), info.getAckStat());
info.setColour(tempColour);
mAlarmListMap.insert(tempIterator, std::pair<CString,ItemInfo>(tagname,info));
}
}
I tried juggling with the allocations, but the increase is always a constant 4.
Could anyone kindly look and highlight where the issue could be?
Thanks a lot.
void FactorySystem::deleteObjectsToBeDeleted()
{
//Delete all objects in the ObjectsToBeDeleted list
std::vector<unsigned>::iterator it = objectsToBeDeleted.begin();
for(unsigned i = 0; i < objectsToBeDeleted.size(); i++)
{
GameObjectIDMapType::iterator it = gameObjectIDMap.find(objectsToBeDeleted[i]);
if(it == gameObjectIDMap.end())
std::cout << "Bad memory or double deletion error!" << std::endl;
else
{
//Delete it and remove its entry in the ID map
std::cout << (it->second->GetID()) << std::endl;
GameObject *object = it->second;
delete object;
gameObjectIDMap.erase(it);
}
}
//All objects to be delete have been deleted
objectsToBeDeleted.clear();
}
At the line where I call delete object, the program just hangs forever, and I can not figure out why. I have googled this problem and it's like nobody has ever encountered this problem ever. I must be doing something bad, but I have no idea what it could be. Any ideas? Thanks.
EDIT:
I was asked to show the destructor for GameObject, here it is:
GameObject::~GameObject()
{
//Delete each component using the component's virtual destructor
//takes care of all resources and memory.
for( ComponentMapIt it = componentMap.begin();it!=componentMap.end();++it)
delete it->second;
}
One other thing to not, I went into the disassembly and was able to step up until:
00488DA9 call GameObject::`scalar deleting destructor' (044055Fh)
and then it just hangs, nothing else happens.
EDIT: Here was my rookie mistake. For some reason I couldn't step into the delete call so I assumed it was in there, but putting a break point in it allowed me to go into it. Thanks everyone, all your suggestions were very helpful.
void PhysicsManager::Unregister(RigidBody *Obj)
{
std::list<RigidBody*>::iterator it = MasterList.begin();
while(it != MasterList.end())
{
if(*it == Obj)
{
MasterList.erase(it);
return;
}
}
}
void PhysicsManager::Unregister(RigidBody *Obj)
{
std::list<RigidBody*>::iterator it = MasterList.begin();
while(it != MasterList.end())
{
if(*it == Obj)
{
MasterList.erase(it);
return;
}
}
}
it is constant and never changes: once the loop start and *it != Obj the loop continues forever
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.