向量迭代和删除

问题描述:

我正在编程一个多线程的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()); 
+0

哦,谢谢你,我是一个C++初学者。我习惯于Java,并没有注意到这一点。谢谢。 – jack 2015-04-02 00:00:50

+1

实际上,如果目标是同时删除该项目并删除该项目,那么'remove_if'将无法在这里工作。如果要使用算法方法,则首先使用'std :: stable_parttion',然后'删除'并擦除分区“坏”一侧的项目。 – PaulMcKenzie 2015-04-02 00:35:53

+0

@PaulMcKenzie:好点,我更新了答案! – 2015-04-02 07:43:43