简体   繁体   中英

How to remove object from a vector if it was deleted

I'm making a console game, where the player can shoot. After the player presses the space bar, a new object is created, placed on the map, and the map contains a pointer to that object. These objects are stored in a vector. I read an article about vectors, where it says:

Vectors are same as dynamic arrays with the ability to resize itself automatically when an element is inserted or deleted

I thought that after I delete an object, vector will automatically shrink, so i did this whenever one of the projectiles hit the wall:

delete entities[x + y * width];
entities[x + y * width] = nullptr;

But the size of the vector didn't change. Do i need to delete the object manually from the vector? I had an idea of making a boolean variable for every projectile where its state is stored (dead/alive), in order to remove it from the vector manually with the help of a loop. Is there a better way of doing that?

And also, is it safe to store projectiles in a vector? I read that vector will copy itself to another segment of the memory when it will reach the maximum size. What will happen to the pointers i have in my map after that?

Code looks something like this:

#include <vector>
#include <iostream>
#include <conio.h>
class Entity {
public:
    int x, y;
    int getX() { return x; }
    int getY() { return y; }
};

class Projectile : public Entity{
public:
    Projectile(int x, int y) {
        this->x = x;
        this->y = y;
    }
};
class Map {
public:
    Entity** entities;
    int width, height;
    Map(int width, int height) {
        this->width = width;
        this->height = height;
    }
    void spawn(Entity* entity) {
        entities[entity->getX() + entity->getY() * width] = entity;
    }
};

int main() {
    Map map(10, 10);
    std::vector<Projectile*> projectiles;

    map.entities = new Entity* [map.width * map.height];
    int x, y;

    while (true) {
        if (_getch() == 32) {
            std::cin >> x >> y;
            projectiles.push_back(new Projectile(x, y));
            map.spawn(*projectiles.begin());
        } 

        //...
        bool hitWall = true;

        if (hitWall) {
            delete map.entities[x + y * map.width];
            map.entities[x + y * map.width] = nullptr;
        }
    }

    return 0;
}

You need to use an iterator. Like this:

entities.erase(entities.begin() + x + y * width)

With regards to safety, for small objects that are instantiated and destroyed often you'd likely be better off storing the objects directly instead of pointers. This removes the possibility of memory leaks or dangling pointers that comes with heap allocation.

From your sample code, I assume your vector is defined somewhat like this:

std::vector<YourType*> entities;

Therefore, your vector does not contain YourType objects, but pointer to YourType . That is, the elements the vector manages are the pointers, not the pointed objects.

Thus when you do this delete entities[x + y * width]; you indeed delete the YourType instance, but the pointer still exists and it sill in your vector.

It might be easier to visualize if you decompose that statement to the equivalent 2 lines:

YourType * pointer = entities[x + y * width];
delete pointer;

To actually remove the pointer from the vector, you need to say so:

entities.erase(entities.begin() + x + y * width);

This would remove the pointer from the array (also shifting all things past that index). You still need to do the delete yourself as, again, the vector is only managing the pointer, not the YourType .


Note that unless you have a good reason, you should probably not store the pointer in the vector, but the object itsself. That would remove your confusion:

std::vector<YourType> entities;

// deleting a YourType:
entities.erase(entities.begin() + x + y * width);

No delete or new anymore, because the object is directly in the vector. So the vector manages it for you instead of just managing the pointer and letting you deal with the pointed object.


Update after question edit:

In your case, you do have a good reason, because you actually store a non-owning pointer. So it might make sense that entities and projectiles store pointers, so they actually point at the same objects.

So both vectors will manage their pointers, but you have to think of how the lifecycle of those two pointers (the one from entities and the one from projectiles) interact with the object itself.

Deleting the object will not get rid of the pointers, in neither of the arrays.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM