在 remove_if 谓词中调用 delete 是否安全?

is it safe to call delete inside a remove_if predicate?

我有一个向量

std::vector<Object*> objects;

以及一个在找到对象时移除对象的方法:

void Remove(Object *o)
{
    objects.erase(
        std::remove_if(
            objects.begin(), objects.end(),
            [&o](Object *_object) {
                if (o == _object)
                {
                    delete _object;
                    return true;
                }
                return false;
            }
        ),
        objects.end()
    );
}

这里安全吗?我不应该打电话给delete吗?但是 erase 会帮我打电话给 delete 吗?我有点困惑。这会使迭代器无效或泄漏内存吗?

Would this invalidate the iterator or leak memory?

内存不会被个别代码泄漏;它被完整的程序泄露了。 必须有人 负责重新分配,但这里没有发生,并不意味着它根本不会发生。 Not 在这里调用 delete 不会“泄漏内存”;泄漏内存的是 整个程序 。这样的代码不能独立存在。

除非遵循既定模式,否则很难找出责任所在。这就是 std::unique_ptr<T>std::shared_ptr<T>std::weak_ptr<T> 等工具存在的原因。请使用它们。

迭代器不会失效。迭代器迭代容器的元素,这些元素本身就是指针。 delete 不影响它所使用的指针。 delete 影响指向内存。

Would erase call delete for me?

没有

Is this safe?

如果任何其他代码可能[=47],这样的代码有双重释放的风险(未定义的行为) =] 尝试 delete 容器中任何 相同指向的元素。

同样,这不是局部风险,而是整个程序的风险。

同样,在整个程序上下文中找出内存管理通常很困难。请根据情况以适当的方式使用标准库工具,如 std::unique_ptr<T>std::shared_ptr<T>std::weak_ptr<T>。关于 C++ 内存管理的正确教程超出了 Stack Overflow 问题的范围。

来自std::remove_if

UnaryPredicate must meet the requirements of Predicate.

从那里开始:

The function object pred shall not apply any non-constant function through the dereferenced iterator. This function object may be a pointer to function or an object of a type with an appropriate function call operator.

(应该可以在同一个元素上调用谓词两次)。

您的谓词不符合该要求,因此代码 不安全

保持你的逻辑,你可以使用 std::partition:

void Remove(/*const*/ Object *o)
{
    auto it = std::partition(objects.begin(), objects.end(),
                             [&o](const Object* object) { return o != object; }
                            );
    for (auto it2 = it; it2 != objects.end(); ++it2) { delete *it2; }
    objects.erase(it, objects.end());
}

但使用智能指针(如 std::unique_ptr(因此 objects 将是 std::vector<std::unique_ptr<Object>> 而不是 std::vector<Object*>))将简化代码:

void Remove(/*const*/ Object *o)
{
    objects.erase(
        std::remove_if(
            objects.begin(), objects.end(),
            [&o](const std::unique_ptr<Object>& object) {
                return o != object.get();
            }
        ),
        objects.end()
    );
}