迭代向量,删除某些项目,因为我去

我有一个 std: : Vector m _ vPath; 我将迭代这个向量并在执行时调用: : 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 _ vPath 的声明如下(在我的类中) :

std::vector<std::string> m_vPaths;
74913 次浏览

看看 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;
}
}

但是你应该使用 ABc1(重造轮子是不好的)。

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

如果有时间擦除一个文件,这可能并不重要,但是我仍然建议向后迭代向量——这样通常可以从向量的末尾(接近)删除项。删除一个项目所花费的时间与向量中该项目后面的项目数成正比。例如,如果您有一个包含100个文件名的向量,并且您成功地删除了所有这些文件名,那么您将在进程中复制最后一个元素100次(并且将第二个元素复制到最后一个元素99次,以此类推)。

OTOH,如果你从最后开始向后工作,你不复制只要删除文件是成功的。您可以使用反向迭代器向后遍历向量,而不需要改变其他任何东西。例如,GMan 使用 move _ if 的代码应该继续工作(只是快一点点) ,只需将 rstart ()替换为 start () ,将 rend ()替换为 end。

另一种可能性是使用 deque 代替矢量—— deque 可以在常量时间内从集合的开始 或者结尾擦除项。