Erasing() an element in a vector doesn't work

If there are at least 3 items in the vector, to delete the last 3 items is simple -- just call pop_back 3 times:

#include <vector>
#include <iostream>

int main() 
{
    std::vector<float> v = { 1, 2, 3, 4, 5 };
    for (int i = 0; i < 3 && !v.empty(); ++i)
       v.pop_back();

    for ( const auto &item : v ) std::cout << item << ' ';
        std::cout << '\n';
}

Output:

1 2

It is undefined behavior to pass the end() iterator to the 1-parameter erase() overload. Even if it weren't, erase() invalidates iterators that are "at and after" the specified element, making d invalid after the 1st loop iteration.

std::vector has a 2-parameter erase() overload that accepts a range of elements to remove. You don't need a manual loop at all:

if (X.size() >= 3)
    X.erase(X.end()-3, X.end());

Live Demo


You could use a reverse_iterator:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<float> X = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6};

    // start the iterator at the last element
    vector<float>::reverse_iterator rit = X.rbegin();

    // repeat 3 times
    for(size_t i = 0; i < 3; i++)
    {
        rit++;
        X.erase(rit.base());
    }

    // display all elements in vector X
    for(float &e: X)
        cout << e << '\n';

    return 0;
}

There are few things to mention:

  • reverse_iterator rit starts at the last element of the vector X. This position is called rbegin.
  • erase requires classic iterator to work with. We get that from rit by calling base. But that new iterator will point to the next element from rit in forward direction.
  • That's why we advance the rit before calling base and erase

Also if you want to know more about reverse_iterator, I suggest visiting this answer.

Tags:

C++

Vector