Удалить и удалить указатели, которые соответствуют условию в векторе - PullRequest
1 голос
/ 01 февраля 2020

У меня есть std::vector, который я хотел бы удалить указатели из вектора, которые удовлетворяют условию isDestroyed(), но также вызвать удаление указателей.

Я сделал следующее, но это требует цикла по вектору в два раза. Есть ли более эффективный способ сделать это?

std::vector<GameObject*> gameObjects;
std::vector<GameObject*> destroyedObjects;
// Get objects to be deleted
std::copy_if (gameObjects.begin(), gameObjects.end(), std::back_inserter(destroyedObjects), [](GameObject* b){return b->isDestroyed();} );
// Remove objects from vector
gameObjects.erase(
    std::remove_if(
            gameObjects.begin(),
            gameObjects.end(),
            [](GameObject* p) { return p->isDestroyed(); }
    ),
    gameObjects.end()
);
// Delete the objects
for (GameObject* o : destroyedObjects)
    delete o;

Ответы [ 3 ]

6 голосов
/ 01 февраля 2020

std::unique_ptr делает удаление бесплатно:

std::vector<std::unique_ptr<GameObject>> gameObjects;

// Remove objects from vector
gameObjects.erase(
    std::remove_if(
            gameObjects.begin(),
            gameObjects.end(),
            [](const auto& p) { return p->isDestroyed(); }
    ),
    gameObjects.end()
);

Я предлагаю использовать его вместо. Это также позволяет избежать ошибок, таких как забвение удаления или двойное удаление.

6 голосов
/ 01 февраля 2020

Это должно работать:

std::vector<GameObject*> gameObjects;
auto end = std::stable_partition(
            gameObjects.begin(),
            gameObjects.end(),
            [](GameObject* p) { !return p->isDestroyed(); }
    );
for (auto i = end; i < gameObjects.end(); i++) {
    delete *i;
}
gameObjects.erase(end, gameObjects.end());
2 голосов
/ 01 февраля 2020

Вам не нужно 2 вектора. Итератор, возвращаемый std::remove_if(), может использоваться, чтобы узнать, какие объекты должны быть delete 'd:

std::vector<GameObject*> gameObjects;
...
auto newEnd = std::remove_if(
    gameObjects.begin(), gameObjects.end(),
    [](GameObject* p) { return p->isDestroyed(); }
);
for(auto iter = newEnd; iter != gameObjects.end(); ++iter) {
    delete *iter;
}
gameObjects.erase(newEnd, gameObjects.end());

Если вы измените свой вектор на std::unique_ptr<GameObject> вместо GameObject*, вы не сможете Больше не нужно delete объектов вручную:

std::vector<std::unique_ptr<GameObject>> gameObjects;
...
gameObjects.erase(
    std::remove_if(
        gameObjects.begin(), gameObjects.end(),
        [](std::unique_ptr<GameObject> &p) { return p->isDestroyed(); }
    ),
    gameObjects.end()
);
...