[英]Vector of pointers element deletion
我有一个指针向量,我想删除一个条目。 删除条目后,我检查向量的大小,并没有减少。 我应该多做一件事吗?
printf("size of vector before %d \n", m_obj.size());
for(std::vector<object*>::iterator it = m_obj.begin(); it != m_obj.end(); ++it)
{
if((*it)->m_id == p_id)
{
delete *it;
}
}
printf("size of vector after %d \n", m_obj.size());
您对delete *it
调用仅删除向量中该条目指向的对象。 您不修改矢量本身。
要从向量中删除元素,请使用erase
方法:
delete *it;
it = m_obj.erase(it);
请注意,擦除会使当前迭代器无效,因此您可能希望将erase
调用的返回值赋给it
变量。 在删除循环中的多个条目时,请注意不要意外跳过元素。 返回的迭代器将指向已删除的元素之后的元素,并将通过for
循环再次递增。
解决此问题的最简单方法是使用STL算法来删除元素。 如果条目也拥有其所有者的所有权,那么这种方法效果最好,因此您可能需要考虑使用智能指针向量(如注释中所示 ),因此您根本不必担心显式调用delete
。
+----------+ +-------------+
| object * |-------->| heap memory |
+----------+ +-------------+
it-------->| object * |-------->| heap memory |
+----------+ +-------------+
| object * |-------->| heap memory |
+----------+ +-------------+
| object * |-------->| heap memory |
+----------+ +-------------+
delete *it
:
+----------+ +-------------+
| object * |-------->| heap memory |
+----------+ +-------------+
it-------->| object * |-------->
+----------+ +-------------+
| object * |-------->| heap memory |
+----------+ +-------------+
| object * |-------->| heap memory |
+----------+ +-------------+
您还需要以某种方式擦除向量中的指针元素。 请记住,在迭代期间不能erase(it)
,因为它会使迭代器失效。
您只释放指针下分配的内存。 你没有删除指针本身。
调用delete后,将指针值设置为NULL。 在for循环之后使用带有NULL的std::remove_if
检查元素。
删除对象不会从向量中删除指向它的指针,它只会释放指针指向的内存。 在释放元素后,您需要在向量上显式调用erase
。
拥有一个拥有 原始指针的STL容器(例如std::vector
)通常是一个坏主意。 这可能是泄漏的来源:例如,如果在某处抛出异常,则会调用向量析构函数,但这不会删除原始拥有指针! 因此他们的相关资源被泄露了。
此外,您必须提供明确的清理代码等。
您可能想要使用std::vector<Object>
或智能指针的std::vector
,例如vector<shared_ptr<Object>>
或vector<unique_ptr<Object>>
(后者可用,因为C ++ 11谢谢移动语义,如果vector
是对象的唯一所有者,并且没有共享所有权,那么这是一个很好的解决方案。
您可能还想使用remove_if()
等算法 。 特别是,要从vector
删除满足某些精确条件的项目,您可能需要使用所谓的erase-remove惯用法 :
// Use a vector of *smart pointers* (shared_ptr or unique_ptr).
typedef std::shared_ptr<Object> ObjectPtr;
std::vector<ObjectPtr> v;
...
...
// Use the erase-remove idiom to erase items satisfying a particular condition.
v.erase( std::remove_if(v.begin(), v.end(), [&](const ObjectPtr & p) {
return p->m_id == deleteId; // Erasing condition
}), v.end());
使代码更清晰(特别是如果一个人不知道/识别擦除 - 删除习语),可以编写一个小帮助函数来实现这个习惯用法:
// Helper function to implement the erase-remove idiom for std::vector.
template <typename T, typename Predicate>
void erase_if(std::vector<T>& v, Predicate p) {
v.erase(std::remove_if(v.begin(), v.end(), p), v.end());
}
然后像这样调用它:
// Simplified code: just pass the vector 'v' and the erasing condition
// (in this case using a simple lambda).
// Uses the erase-remove idiom under the hood.
//
erase_if(v, [&](const ObjectPtr & p) { return p->m_id == deleteId; });
请注意,由于使用了remove_if
算法和erase-remove习惯用法,因此提高了代码的语义级别 :您不会读取显式for
循环和迭代器递增; 你可以只读取代码的明确意图 ,即删除满足给定条件的项目。
PS :您可能还想阅读: “如何从STL容器中擦除元素?” 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.