在 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 问题的范围。
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()
);
}
我有一个向量
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
calldelete
for me?
没有
Is this safe?
如果任何其他代码可能[=47],这样的代码有双重释放的风险(未定义的行为) =] 尝试 delete
容器中任何 相同指向的元素。
同样,这不是局部风险,而是整个程序的风险。
同样,在整个程序上下文中找出内存管理通常很困难。请根据情况以适当的方式使用标准库工具,如 std::unique_ptr<T>
、std::shared_ptr<T>
和 std::weak_ptr<T>
。关于 C++ 内存管理的正确教程超出了 Stack Overflow 问题的范围。
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()
);
}