I have a std::vector m_vPaths; I will iterate this vector and call ::DeleteFile(strPath) as I go. If I successfully delete the file, I will remove it from the vector. My question is can I get around having to use two vectors? Is there different data structure that might be better suited for what I need to do?
example: using iterators almost does what I want, but problem is once you erase using an iterator, all iterators become invalid.
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. } }
I can use two vectors and I will no longer have a problem, but is there a better, more efficient method of doing what I'm trying to do?
btw, incase it is unclear, m_vPaths is declared like this (in my class):
std::vector<std::string> m_vPaths;
The erase() function can remove an element from the beginning, within, or end of the vector. In order to remove all the elements from the vector, using erase(), the erase() function has to be repeated the number of times there are elements, beginning from the first element.
If you need to remove multiple elements from the vector, the std::remove will copy each, not removed element only once to its final location, while the vector::erase approach would move all of the elements from the position to the end multiple times.
The erase()
method returns a new (valid) iterator that points to the next element after the deleted one. You can use this iterator to continue with the loop:
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; }
Check out 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());
Use a std::list
to stop the invalid iterators problem, though you lose random access. (And cache performance, in general)
For the record, the way you would implement your code would be:
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; } }
But you should use std::remove_if
(reinventing the wheel is bad).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With