迭代向量,删除某些项目

cch*_*ion 62 c++ iterator loops vector data-structures

我有一个std :: vector m_vPaths; 我会迭代这个向量并调用:: DeleteFile(strPath).如果我成功删除了该文件,我将从矢量中删除它.我的问题是,我可以使用两个向量吗?是否有不同的数据结构可能更适合我需要做的事情?

示例:使用迭代器几乎可以实现我想要的,但问题是一旦使用迭代器擦除,所有迭代器都将变为无效.

 std::vector<std::string> iter = m_vPaths.begin();
    for( ; iter != m_vPaths.end(); iter++) {
        std::string strPath = *iter;
        if(::DeleteFile(strPath.c_str())) {
            m_vPaths.erase(iter);   
                //Now my interators are invalid because I used erase,
                //but I want to continue deleteing the files remaining in my vector.    
        }
    }
Run Code Online (Sandbox Code Playgroud)

我可以使用两个向量,我将不再有问题,但是有没有更好,更有效的方法来做我想做的事情?

顺便说一句,如果不清楚,m_vPaths就是这样声明的(在我的课上):

std::vector<std::string> m_vPaths;
Run Code Online (Sandbox Code Playgroud)

sth*_*sth 119

erase()方法返回一个新的(有效)迭代器,该迭代器指向删除后的下一个元素.您可以使用此迭代器继续循环:

std::vector<std::string>::iterator iter;
for (iter = m_vPaths.begin(); iter != m_vPaths.end(); ) {
    if (::DeleteFile(iter->c_str()))
        iter = m_vPaths.erase(iter);
    else
        ++iter;
}
Run Code Online (Sandbox Code Playgroud)

  • 对于`std :: map`,你可以使用`erase(iter ++);`因为`erase`不会使其他迭代器无效而不会被擦除. (4认同)
  • @averagejoe:如果你这样做,`erase()`返回的迭代器会递增以进行下一次循环迭代.但是你不希望它增加 - "erase()"为下一个循环迭代返回正确的迭代器,另外增加它会跳过一个元素. (4认同)
  • 微妙.我差点把这个看成是因为我认为擦除会使以下的迭代器无效.谢谢你的链接. (2认同)

GMa*_*ckG 75

退房std::remove_if:

#include <algorithm> // for remove_if
#include <functional> // for unary_function

struct delete_file : public std::unary_function<const std::string&, bool> 
{
    bool operator()(const std::string& strPath) const
    {
        return ::DeleteFile(strPath.c_str());
    }
}

m_vPaths.erase(std::remove_if(m_vPaths.begin(), m_vPaths.end(), delete_file()),
                m_vPaths.end());
Run Code Online (Sandbox Code Playgroud)

std::list尽管您丢失了随机访问权限,但使用a 来停止无效迭代器问题.(和缓存性能一般)


为了记录,您实现代码的方式是:

typedef std::vector<std::string> string_vector;
typedef std::vector<std::string>::iterator string_vector_iterator;

string_vector_iterator iter = m_vPaths.begin();
while (iter != m_vPaths.end())
{
    if(::DeleteFile(iter->c_str()))
    {
        // erase returns the new iterator
        iter = m_vPaths.erase(iter);
    }
    else
    {
        ++iter;
    }
}
Run Code Online (Sandbox Code Playgroud)

但你应该使用std::remove_if(重新发明轮子是坏的).


Jer*_*fin 7

考虑到擦除文件的时间,它可能没关系,但我仍然建议向后迭代向量 - 这样你通常会从向量的末尾删除项目(接近).删除项目所花费的时间与向量中跟随项目的项目数量成正比.如果(例如)您有一个包含100个文件名的向量,并且您成功删除了所有文件名,则您将在该过程中复制最后一个元素100次(并将第二个元素复制到最后一个元素99次,依此类推).

OTOH,如果你从最后开始并向后工作,只要删除文件成功,就不会复制.您可以使用反向迭代器向后遍历向量而不会更改其他任何内容.例如,使用remove_if的GMan代码应该继续工作(仅稍微快一点),只需将rbegin()替换为begin(),将rend()替换为end.

另一种可能性是使用deque而不是vector - deque可以在恒定时间内从集合的结尾开头擦除项目.