SFML community forums

Help => General => Topic started by: prchakal on December 03, 2010, 10:30:26 pm

Title: How to remove class/sprite
Post by: prchakal on December 03, 2010, 10:30:26 pm
Hi,

On my game i have a vector with all my enemies, and i want that when it collide with some other objects, be removed from vector and destroyed.

My vector:

Code: [Select]
static std::vector<Enemy*> *enemies;

What i have tested:

Code: [Select]
void Enemy::remove()
{
//GameObjects::enemies->erase(*this);
//delete this;

for (std::vector<Enemy*>::iterator it = GameObjects::enemies->begin(); it!=GameObjects::enemies->end(); ++it) {
if (((Enemy*)*it) == this)
{
GameObjects::enemies->erase(it);
}
}
}


But allways that i do it, i get a fatal error.
Title: How to remove class/sprite
Post by: Laurent on December 03, 2010, 10:37:39 pm
First solution:
Code: [Select]
void Enemy::remove()
{
    GameObjects::enemies->erase(std::find(GameObjects::enemies.begin(), GameObjects::enemies.end(), this));
}


Second one:
Code: [Select]
void Enemy::remove()
{
    for (std::vector<Enemy*>::iterator it = GameObjects::enemies->begin(); it != GameObjects::enemies->end(); ++it)
    {
        if (*it == this)
        {
            GameObjects::enemies->erase(it);
            break;
        }
    }
}
Title: How to remove class/sprite
Post by: Orwel on December 03, 2010, 11:26:33 pm
You should remove your entity from GameObjects at end of loop. You can use a message for GameObjects as

Code: [Select]

void Enemy::remove()
{
       GameObjects::atRemove(this);
}
....
void GameObjects::atRemove(Enemy *e)
{
       listAtRemove.push_back(e);
}

//Call end of loop, to avoid calls of entity
void GameObjects::removeEnemys()
{
  ....//Remove the objects of the list in GameObjects::enemies
}
Title: How to remove class/sprite
Post by: prchakal on December 04, 2010, 07:29:00 am
Hi,

I resolve the problem with:

Code: [Select]

for (long x = 0; x < (long)GameObjects::enemies->size(); ++x)
{
Enemy *enemy = GameObjects::enemies->at(x);

if (enemy == this)
{
GameObjects::enemies->erase(GameObjects::enemies->begin() + x);
}

}



When i erase an element from vector, it is all removed from the memory?
Title: How to remove class/sprite
Post by: Laurent on December 04, 2010, 09:18:32 am
Quote
I resolve the problem with

Not the best one. You shouldn't ignore our replies ;)

Quote
When i erase an element from vector, it is all removed from the memory?

The pointer is removed from the vector, but the object is not destroyed, you still have to call delete.
Title: How to remove class/sprite
Post by: Svenstaro on December 04, 2010, 01:05:36 pm
You should really use boost::ptr_vector<Enemy> or std::vector< boost::shared_ptr<Enemy> > instead.
Title: How to remove class/sprite
Post by: prchakal on December 04, 2010, 05:05:15 pm
Hey laurent,

Sorry man, i dont see your posts.

Now i change my solution for yours, its simply perfect.

Thanks very much, it help a lot.
Title: How to remove class/sprite
Post by: prchakal on December 04, 2010, 05:16:39 pm
Hi,

The problem is that if im in the loop, and a method in this loop remove an element from the vector, the program crashes, an example:

Code: [Select]

for (std::vector<Enemy*>::iterator it = GameObjects::enemies->begin(); it!=GameObjects::enemies->end(); ++it) {
((Enemy*)*it)->update();
}


The update check the collision and call remove method:

Code: [Select]
if (Collision::PixelPerfectTest(sprite, GameObjects::planet->getSprite()))
{
GameObjects::enemies->erase(std::find(GameObjects::enemies->begin(), GameObjects::enemies->end(), this));
}



When ERASE method is called, the program crashes.
Title: How to remove class/sprite
Post by: Hiura on December 04, 2010, 05:33:22 pm
maybe something about vector::erase (http://www.dinkumware.com/manuals/?manual=compleat&page=vector.html#vector::erase)
Quote
Erasing N elements causes N destructor calls and an assignment for each of the elements between the insertion point and the end of the sequence. No reallocation occurs, so iterators and references become invalid only from the first element erased through the end of the sequence.
Title: How to remove class/sprite
Post by: prchakal on December 04, 2010, 07:05:55 pm
Hi,

What i do to prevent it, is make a loop on this vector objects without look it, an example:

Code: [Select]
for (long x = 0; x < (long)GameObjects::enemies->size(); ++x)
{
    Enemy *enemy = GameObjects::enemies->at(x);
    ...
    enemy->remove();
}


The remove method is:

Code: [Select]
GameObjects::enemies->erase(std::find(GameObjects::enemies->begin(), GameObjects::enemies->end(), this));

So, when i need loop vectors, i will use FOR without iterator, then i can remove without problems.

With this solution my problem is solved.

This is a good practice?
Title: How to remove class/sprite
Post by: Hiura on December 04, 2010, 11:53:27 pm
Yes, it seems good to me.
Title: How to remove class/sprite
Post by: Nexus on December 06, 2010, 08:02:12 pm
To me, it doesn't.
Title: How to remove class/sprite
Post by: Hiura on December 06, 2010, 11:19:56 pm
It seems to me I didn't read deep enough.  :roll:

Good advices here!
Title: How to remove class/sprite
Post by: prchakal on December 09, 2010, 09:46:43 pm
So nexus, what you recommend?
Title: How to remove class/sprite
Post by: prchakal on December 09, 2010, 10:05:24 pm
To delete the class from memory, i invoke:

Code: [Select]
delete this;

And now the destructor is called.
Title: How to remove class/sprite
Post by: Nexus on December 09, 2010, 11:28:11 pm
Quote from: "prchakal"
So nexus, what you recommend?
I have already given you some improvement suggestions, so I don't know what you mean.

Quote from: "prchakal"
To delete the class from memory, i invoke:
Code: [Select]
delete this;And now the destructor is called.
I wouldn't do that. In the very most cases, the instance which is in charge of allocating the object should also deallocate it for symmetry reasons. With your approach, you enforce the use of the new operator and therefore manual memory management (which should be avoided wherever possible). One can neither lay an Enemy on the stack, nor create a temporary object of it, nor put it inside a smart-pointer.

If I were you, I would either use Boost's pointer containers (the probably best approach), or delete each element before it is erased. If you have the TR1, std::tr1::shared_ptr might be an alternative.
Title: How to remove class/sprite
Post by: prchakal on December 10, 2010, 02:54:44 pm
Hi,

With boost smartpointer, when i do the ERASE from vector it will be deleted?

Do you have a function example?
Title: How to remove class/sprite
Post by: Nexus on December 11, 2010, 01:05:45 pm
Quote from: "prchakal"
With boost smartpointer, when i do the ERASE from vector it will be deleted?
Yes. As soon as the smart-pointer object is destroyed, the memory is deallocated. But if you are already using Boost, you should try the pointer-containers. They are much more specialized and optimized for this purpose.

Anyway, I wonder why you need pointers. Do you need polymorphism, or are your Enemy instances noncopyable or unique? If not, the straightforward approach is to store Enemy objects using STL containers:
Code: [Select]
std::vector<Enemy> v;
v.push_back( Enemy(...) );
v[0].Attack();
v.erase(v.begin());             // Memory is freed

Then the Boost pointer-container approach, storing Enemy* pointers:
Code: [Select]
boost::ptr_vector<Enemy> v;
v.push_back( new Enemy(...) );  // Insert pointer to object
v[0].Attack();                  // No additional dereferencing (no ->, just .)
v.erase(v.begin());             // Memory is freed