删除和删除与向量中的条件匹配的指针

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&lt;GameObject&gt; 而不是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

以上是关于删除和删除与向量中的条件匹配的指针的主要内容,如果未能解决你的问题,请参考以下文章

用于删除 Map 中的指针值和指针向量的 C++ 通用代码

删除向量中的指针会导致错误

C ++通过索引删除指针向量中的值[关闭]

在删除指向动态分配对象的指针向量中的元素之前,我需要做啥?

从数组中删除与 PHP 中的特定条件匹配的项目

删除与ag-grid中的筛选条件匹配的记录