删除和删除与向量中的条件匹配的指针
Posted
技术标签:
【中文标题】删除和删除与向量中的条件匹配的指针【英文标题】:Remove and delete pointers that match a condition in a vector 【发布时间】:2020-02-01 19:22:05 【问题描述】:我有一个std::vector
,我想从满足isDestroyed()
条件的向量中删除指针,但还要对指针调用delete。
我做了以下操作,但它需要在向量上循环两次。有没有更有效的方法?
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;
【问题讨论】:
向相反方向循环,这样您就可以在不移动其他迭代器的情况下删除一个元素。 【参考方案1】: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()
);
我建议改用它。也避免了忘记删除或重复删除等错误。
【讨论】:
【参考方案2】:这应该可行:
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());
【讨论】:
What does this code do? 这不能保证有效,因为remove_if
未指定范围的已删除部分中的值。它们不需要(根据我的经验也不会)与被删除的值一一对应。
@Kyle,你是对的(我从来没有使用过 remove_if
用于擦除以外的任何东西),stable_partition
应该可以完成这项工作【参考方案3】:
您不需要 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()
);
【讨论】:
@walnut 在这种情况下并不重要 您不能使用remove_if
返回的迭代器和结束之间的值,因为该范围内的值是未指定的,因此删除它们可能会导致UB。在这种情况下使用unique_ptr
很好,并且会做正确的事情。如果您想要一个可以在擦除之前安全删除已删除指针的实现,则需要改用std::partition
。以上是关于删除和删除与向量中的条件匹配的指针的主要内容,如果未能解决你的问题,请参考以下文章