In your situation, I think that there are two problems worth being taken in account:
- you are using a container with contiguous indices, so that every time an element is removed, all the elements after it get reindexed (and that's the reason why you had to do the removal in reverse order in your sample code),
- that container also happens to store its elements contiguously, so that any deletion may trigger a reallocation, and at least provoque a copy of elements to satisfy the continuousness constraint.
Given these two issues, it might be interesting in some cases to copy the elements you wish to keep over to a new container, rather than do the removal. In your case, it appears that copying the elements should not be a big concern, as many implementations of std::string use a copy on write strategy, but you might want to verify that with your own.
Another thing to consider is that the set of indices to be removed can be nicely stored in a bit vector. It's fairly efficient, and simplify the algorithm significantly. You'll need to keep track of the effective number of elements removed though.
I would personally go for a simple loop, but C++ offers many ways to achieve a similar result. Here's the loop version:
std::vector<bool> remove_these(my_vec.size(), false): remove_these[0] = remove_these[4] = true; std::vector<std::string> my_result; my_result.reserve(my_vec.size() - 2); for (int i = 0; i < remove_these.size(); ++i) if (!remove_these[i]) my_result.push_back(my_vec[i]);
Note the use of reserve to avoid multiple reallocations during the vector filling.
Now, all is left to do is wrap the above code in a function which will transform beforehand the int vector in a bool vector:
template <typename IT> void erase(std::vector<std::string> &my_vec, IT begin, IT end){ std::vector<std::string> res; std::vector<bool> r(my_vec.size(), false); res.reserve(my_vec.size() - (end - begin)); for (IT it = begin; it != end; ++it) r[*it] = true; for (int i = 0; i < r.size(); ++i) if (!r[i]) res.push_back(my_vec[i]); my_vec = res; }
That would be it. The time complexity of the algorithm is about O(N+M), where N and M are the sizes of my_vec and remove_these. Alternatively, one could replace the second loop with a remove_if.
In fact, if the stl provided a function to iterate over a sequence like remove_if and call a predicate function taking in parameter the key and value of that iterator, we could use it by feeding it with my_vec reverse iterators, and a lambda to check if the given key is in remove_these, but the time complexity would be a bit higher than the solution above.