我有一个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 :(得分:114)
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;
}
答案 1 :(得分:73)
#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
(重新发明轮子很糟糕)。
答案 2 :(得分:7)
考虑到擦除文件的时间,它可能没关系,但我仍然建议向后迭代向量 - 这样你通常会从向量的末尾删除项目(接近)。删除项目所花费的时间与向量中跟随项目的项目数量成正比。如果(例如)您有一个包含100个文件名的向量,并且您成功删除了所有文件名,则您将在该过程中将最后一个元素复制100次(并将第二个元素复制到最后一个元素99次,依此类推)。
OTOH,如果从最后开始并向后工作,只要删除文件成功,就不会复制。您可以使用反向迭代器向后遍历向量而不会更改其他任何内容。例如,使用remove_if的GMan代码应该继续工作(仅稍微快一点),只需将rbegin()替换为begin(),将rend()替换为end。
另一种可能性是使用deque而不是vector - deque可以在恒定时间内从结尾或中删除项目的开头。