C++ 迭代向量,在执行时删除某些项

C++ 迭代向量,在执行时删除某些项,c++,data-structures,vector,loops,iterator,C++,Data Structures,Vector,Loops,Iterator,我有一个std::vector m_vPaths;我将迭代这个向量,并在运行时调用::DeleteFile(strPath)。如果我成功删除该文件,我将从向量中删除它。我的问题是,我可以不用使用两个向量吗?是否有不同的数据结构更适合我需要做的事情 例如: 使用迭代器几乎可以满足我的要求,但问题是一旦使用迭代器擦除,所有迭代器都将无效 std::vector<std::string> iter = m_vPaths.begin(); for( ; iter != m_vPat

我有一个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.    
        }
    }
std::vector iter=m_vPaths.begin();
对于(;iter!=mvpaths.end();iter++){
std::string strPath=*iter;
if(::DeleteFile(strPath.c_str())){
mvpaths.擦除(iter);
//现在我的interator无效了因为我用了擦除,
//但是我想继续删除向量中剩余的文件。
}
}
我可以使用两个向量,我就不会有问题了,但是有没有更好、更有效的方法来做我想做的事情呢

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

std::向量m_vpath;
签出:

但是您应该使用(重新发明轮子是不好的)。

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

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;
}
std::vector::iter;
对于(iter=m_vPaths.begin();iter!=m_vPaths.end();){
如果(::DeleteFile(iter->c_str())
iter=路径擦除(iter);
其他的
++iter;
}

如果有时间擦除文件,这可能无关紧要,但我仍然建议向后遍历向量——这样通常会从向量末尾(接近)删除项目。删除项目所需的时间与向量中紧随其后的项目数成比例。例如,如果您有一个包含100个文件名的向量,并且您成功地删除了所有文件名,那么您将在该过程中复制最后一个元素100次(并将第二个元素复制到最后一个元素99次,以此类推)

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


另一种可能是使用deque而不是矢量——deque可以在固定时间内从集合的末尾或开头删除项。

此外,我不知道它使用的是哪种数据结构,如果有比矢量更好的数据结构,请告诉我。我不认为std::queue或std::list对我有任何帮助(尽管我可能错了:)。我几乎否决了这一点,因为我认为擦除将使以下迭代器无效。感谢您的链接。但是,这种方法不适用于所有STL容器(特别是std::map),而擦除(范围)/移除组合适用于任何STL容器。对于
std::map
,您可以使用
erase(iter++)因为有
erase
不会使除已删除的迭代器之外的其他迭代器无效。将“++iter”作为foor循环的正常第三个表达式实际上是不正确的吗?如果n-1被擦除,那么这样做似乎会导致它跳过元素n。@averagejoe:如果这样做,则由
erase()
返回的迭代器在下一个循环迭代中递增。但是您不希望它递增-
erase()
为下一个循环迭代返回了正确的迭代器,另外递增它会跳过一个元素。将第n个好项移动到第n个索引不是更好吗?我们只需要索引位置值,一个用于第n个好的项目位置,另一个用于第n个索引。这将确保所有好的项目向前移动,一旦完成,我们可以将向量调整为n个元素(不确定是否支持)。最多,在删除第一个元素时,会发生n-1交换。
#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());
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;
    }
}
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;
}