2009-10-22 111 views
48

我有一个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.  
     } 
    } 

我可以用两个向量和我将不再有问题,但有没有这样做我想要做的更好的,更有效的方法?

顺便说一句,柜面目前还不清楚,m_vPaths声明如下(在我的课):

std::vector<std::string> m_vPaths; 
+0

此外,我不''真正的情况下,它使用什么样的数据结构,如果有更好的东西比矢量让我知道。我不认为std :: queue或std :: list有任何帮助我的东西(虽然我可能是错的:) – cchampion 2009-10-22 01:43:23

回答

67

退房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()); 

使用std::list制止无效的迭代器的问题,尽管你失去了随机访问。 (和缓存性能,在一般情况)


根据记录,你会实现你的代码将是这样:

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::remove_if(重新发明轮子是坏的)。

90

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; 
} 
+2

微妙。我几乎低估了这一点,因为我认为擦除会使以下迭代器无效。感谢您的链接。 – 2009-10-22 13:57:32

+0

但是,这种方法不适用于所有STL容器(特别是std :: map),而擦除(范围)/删除组合适用于任何STL容器。 – 2009-10-22 19:10:18

+3

对于'std :: map',您可以使用'erase(iter ++);'因为'erase'不会使其他迭代器失效,而不会使其他迭代器失效。 – sth 2009-10-22 19:18:51

7

给删除文件的时候,它可能并不重要,但我还是劝通过向后矢量迭代 - 这样你”通常从(接近)向量的末尾删除项目。删除项目所用的时间与向量中的项目数量成正比。如果(例如)有一个包含100个文件名的矢量,并且您成功删除了所有这些文件名,则会在该过程中将最后一个元素复制100次(并将第二个元素复制到最后一个元素99次,依此类推)。

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

另一种可能是使用deque而不是矢量 - deque可以在最后的这个集合的开始时间内擦除项目。

+0

将第n个物品移动到第n个索引不是更好吗?我们只需要索引位置值,一个用于第n个物品位置,另一个用于第n个索引。这将确保所有优质项目向前移动,一旦完成,我们可以将矢量调整为n个元素(不确定是否支持)。至多,当第一个元素被删除时,n-1交换发生。 – saurabheights 2017-05-28 10:10:05