3

std::vector::erase() does not accept reverse iterator.
Is there any way to call this method with a reverse iterator?

My sample code is:

std::vector<int> MyVector;
for (int i=0; i<10; i++)
{
    MyVector.push_back(i);
}
// Now suppose that I want to erase the last three elements
int nEraseCount = 0;
for (std::vector<int>::const_reverse_iterator it=MyVector.rbegin();
        it<MyVector.rend(); ++it)
{
    MyVector.erase(it);
    if (++nEraseCount == 3) break;
}

However, this sample code is not working, because it is a reverse iterator and erase() does not take reverse iterator as its argument.

How do I modify this code so that it works?

hkBattousai
  • 10,583
  • 18
  • 76
  • 124
  • 1
    Even if the iterators were compatible, erase will invalidate them and cause your iteration to fail. Better employ the remove-erase idiom! – ltjax Jan 07 '11 at 12:17
  • Is your code a simplified example where you need reverse iterator or are you trying to remove the last three elements from a vector? – Martin York Jan 07 '11 at 12:40

5 Answers5

7

You can convert from reverse_iterators to iterators using base() although you need to subtract one to get the one that points to the same element thus rbegin() points to end() and rend() points to begin() (because it is not possible to point to one before the beginning in reality).

You have more of a problem because you are using a const_reverse_iterator which cannot be converted to a non-const one and erase requires non-const iterators. The logic is that you are modifying the collection so you use a non-const iterator.

In your case, you have a bigger problem with your loop as you are removing iterators thus invalidating them, then trying to move back to the previous element.

If you need to remove the last 3 elements then you should use an erase method that takes a range rather than remove them one at a time.

This can be done using MyVector.erase(MyVector.rbegin() + 3).base(), MyVector.end() ) in this particular case as long as you know that MyVector.size() >= 3

CashCow
  • 30,981
  • 5
  • 61
  • 92
  • What should I write instead of "MyVector.erase(it);" in my code? – hkBattousai Jan 07 '11 at 12:28
  • If you removing a range then get the whole range then call the version of erase that takes 2 iterators. If you are removing based on a predicate use the erase/remove_if idiom – CashCow Jan 07 '11 at 12:38
5

I would workaround the problem by not using a reverse iterator. I'll probably write something like that:

std::vector<int> MyVector;
for (int i=0; i<10; i++)
{
    MyVector.push_back(i);
}
// Now suppose that I want to erase the last three elements
int nEraseCount = 0;
while (nEraseCount < 3 && !MyVector.empty())
{
    MyVector.pop_back();
    ++nEraseCount;
}
Sylvain Defresne
  • 42,429
  • 12
  • 75
  • 85
4

Okay you have several options - you are erasing from the end - so you could:

resize()

if (MyVector.size() > 3)
  MyVector.resize(MyVector.size() - 3);
else
  MyVector.clear(); // presumably you don't want all anyway!

simple difference

if (MyVector.size() > 3)
  MyVector.erase(MyVector.end() - 3, MyVector.end());
else
  MyVector.clear(); // presumably you don't want all anyway!

The approach you've taken is not very idiomatic

Nim
  • 33,299
  • 2
  • 62
  • 101
3

If you just want to remove N elements at the back:

size_t N = 3;
size_t to_remove = std::min(vec.size(), N);
vec.erase(vec.end() - to_remove, vec.end());
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
1

You cannot pass const_iterator or const_reverse_iterator to erase(), as it is readonly iterator!

You should use non-const forward iterator version : std::vector<int>::iterator.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • @Downvoter : please specify the reason. At least let me know where I'm wrong! – Nawaz Jan 07 '11 at 12:43
  • 1
    `erase` requires `iterator` argument(s), not `const_iterator` - so almost all of your answer is wrong. – JoeG Jan 07 '11 at 12:46
  • @Joe : I posted the function signature also. Please see that. It will work with BOTH! – Nawaz Jan 07 '11 at 12:51
  • It takes iterator in C++98 and C++03 - it will take const_iterator in C++0x. – JoeG Jan 07 '11 at 12:57
  • @Nawaz, unless it's your compiler specific, `erase()` expects a non `const_iterator`. You'll get a compile error if you try to pass in a `const_iterator` into erase. See this: http://ideone.com/Xev5w – Nim Jan 07 '11 at 13:00
  • @Joe : I'm using MSVC++08, which is C++03. – Nawaz Jan 07 '11 at 13:03
  • @Nim : That makes sense. :-) In fact, that is what I expected when I first wrote my answer. But when I say MSVC++03 implementation, I changed that. Let me rollback my answer. :D – Nawaz Jan 07 '11 at 13:08
  • It's still wrong, `erase` takes `iterator` only, not `reverse_iterator`. – JoeG Jan 07 '11 at 13:10
  • @Joe : Yeah, I edited that portion of my answer. You're too quick to reply. :) – Nawaz Jan 07 '11 at 13:11