迭代vector,去掉某些项目
我有一个std ::向量m_vPaths; 我将迭代这个向量,并随时调用:: DeleteFile(strPath)。 如果我成功删除了文件,我会从vector中删除它。 我的问题是我可以绕过不得不使用两个向量? 有不同的数据结构可能更适合我需要做的吗?
例如:使用迭代器几乎做我想要的,但问题是一旦你使用迭代器擦除,所有迭代器变得无效。
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是这样宣布(在我的class级):
std::vector<std::string> m_vPaths;
退房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
来停止无效的迭代器问题,尽pipe你失去了随机访问。 (和一般的caching性能)
为了logging,你将实现你的代码的方式是:
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
(重新发明轮子是坏的)。
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; }
考虑到擦除文件的时间,这可能并不重要,但我仍然build议反向遍历向量 – 这样,通常从(接近)向量的末尾删除项目。 删除项目所用的时间与向量中的项目数目成正比。 如果(例如)有100个文件名称的vector,并且您成功删除了所有这些文件名称,则会在过程中复制最后一个元素100次(并将第二个元素复制到最后一个元素99次,依此类推)。
OTOH,如果从最后开始向后工作,只要删除文件成功就不复制。 您可以使用反向迭代器向后遍历向量,而不会改变其他任何东西。 例如,使用remove_if的GMan代码应该继续工作(只需要稍微快点),只需将rbegin()replace为begin(),然后将rend()replace为end。
另一种可能是使用一个deque而不是一个vector–一个deque可以在一段时间内从集合的末尾或者开始删除这些物品。