向量迭代和删除
问题描述:
我正在编程一个多线程的c + + WIN套接字服务器,我遇到了一些奇怪的问题。向量迭代和删除
我正在使用矢量来存储活动连接。我用win mutex锁定向量,然后尝试遍历它以查找所有关闭的连接并删除它们,然后释放互斥锁。
代码:
if (!m_activeConnections.empty()){
for(std::vector<Connection*>::iterator it = m_activeConnections.begin(); it != m_activeConnections.end(); ++it) {
if ((*it)->isClosed()){
delete *it;
it = m_activeConnections.erase(it);
break;
}
}
cout << "\n \t Active Connections: " << m_activeConnections.size() << endl;
}
它是这样工作的,但是当我删除break
线总是去与迭代it
指向一个更在循环和值为0xAAAAAA抛出异常。如果这个删除是在创建新连接的同一个线程中完成的,即使没有中断,它也可以正常工作。为什么是这样?
答
无论何时您修改范围,您都必须确保更新了用于遍历范围的迭代器,这种方式与从范围中删除时迭代器失效的方式相兼容。
将此方法应用于矢量的一个简单示例是以下循环。请注意,从擦除点开始,擦除将使所有迭代器无效,因此当擦除时需要获取新的迭代器,并且每次都需要重新计算end()
(即,不要将末端计算提升到循环外):
for (auto it = m_activeConnections.begin(); it != m_activeConnections.end();)
{
if ((*it)->isClosed()) { it = m_activeConnections.erase(it); }
else { ++it; }
}
从矢量中擦除的更好方法是将要擦除的元素移动到矢量的后面,然后一次擦除整个范围,并避免始终移动尾部范围。一般来说,我们做这个有remove_if
,但你需要添加一点取巧的同时删除你的情况指针对象:
m_activeConnections.erase(
std::remove_if(m_activeConnections.begin(),
m_activeConnections.end(),
[](Connection * p) {
if (p->isClosed()) { delete p; return true; }
return false;}),
m_activeConnections.end());
,如果你改变了你的容器std::vector<std::unique_ptr<Connection>>
你可能避免挂羊头卖狗肉:让每个负责一个班(矢量包含,唯一指针删除),算法变得可组合。第一个分区的范围内根据需要删除,然后删除,然后删除范围:
如果你不能让你的代码简单的通过选择适当的抽象,你也可以尝试更复杂的算法
auto it = std::stable_partition(m_activeConnections.begin(),
m_activeConnections.end(),
[](Connection * p) { return p->isClosed(); });
for (auto kt = it; kt != m_activeConnections.end(); ++kt)
{
delete *kt;
}
m_activeConnections.erase(it, m_activeConnections.end());
哦,谢谢你,我是一个C++初学者。我习惯于Java,并没有注意到这一点。谢谢。 – jack 2015-04-02 00:00:50
实际上,如果目标是同时删除该项目并删除该项目,那么'remove_if'将无法在这里工作。如果要使用算法方法,则首先使用'std :: stable_parttion',然后'删除'并擦除分区“坏”一侧的项目。 – PaulMcKenzie 2015-04-02 00:35:53
@PaulMcKenzie:好点,我更新了答案! – 2015-04-02 07:43:43