10

I created a simple C++ program to test the behaviour of erase() in C++ vectors.

This is my code:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    // your code goes here

    vector<int> vec;

    vec.push_back(3);
    vec.push_back(4);
    vec.push_back(5);

    cout << vec[0] << " " << vec[1] << " " << vec[2] << endl;

    vec.erase(vec.end());
    //vec.erase(vec.begin());

    cout << vec.size() << endl;

    vec.push_back(12);
    vec.push_back(10);

    cout << vec[0] << " " << vec[1] << " " << vec[2] << endl;


    return 0;
}

The problem is the above code is giving segmentation fault when trying to erase the last element from the vector. But when I erase the first element using begin(), it is working fine. I am unable to understand the reason behind it. Any help would be highly appreciated.

Bhawan
  • 2,441
  • 3
  • 22
  • 47
  • 1
    Possible duplicate of [Erasing vector::end from vector](https://stackoverflow.com/questions/9590117/erasing-vectorend-from-vector), [Erasing vector.end() fails](https://stackoverflow.com/q/29530190/608639), [Why erasing vector.end() is allowed?](https://stackoverflow.com/q/34415407/608639) and friends. – jww Feb 22 '18 at 07:18
  • 1
    Possible duplicate of [Erasing vector.end() fails](https://stackoverflow.com/questions/29530190/erasing-vector-end-fails) – Fantastic Mr Fox Feb 22 '18 at 07:21
  • Also see [Why are Standard iterator ranges \[begin, end) instead of \[begin, end\]?](https://stackoverflow.com/q/9963401/608639) – jww Feb 22 '18 at 07:45
  • @KillzoneKid Nope, `.back()` is the equivalent of `*(.end() - 1)`. It returns a reference to the last element, not an iterator. You cannot use it for erasing an element of a vector. – Fantastic Mr Fox Feb 22 '18 at 23:02
  • @FantasticMrFox So close yet so far ;) – Killzone Kid Feb 22 '18 at 23:15

5 Answers5

20

The problem is that std::vector::end returns an iterator to the element following the last element of the container, not to the last element.

What you want should be

vec.erase(vec.end() - 1); // trying to erase the last element of vec
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Will it erase the last element ? I guess it will erase the second last element of the vector. – Bhawan Feb 22 '18 at 07:04
  • @BhawandeepSingla `vec.erase(vec.end() - 1);` will erase the last element. As my answer explained, the iterator returned by `std::vector::end` points to the position following the last element. – songyuanyao Feb 22 '18 at 07:12
  • 1
    Who down voted this ... ? It is an exactly correct answer. – Fantastic Mr Fox Feb 22 '18 at 07:22
  • The question and subsequent answers are not really useful. They add nothing of value to the site. The answer might even promote more bad questions. This particular answer has been provided at least nine times in earlier questions. – jww Feb 22 '18 at 07:35
  • Stack Overflow is full of plenty of opinions... [Should we downvote answers to obvious duplicate questions?](https://meta.stackexchange.com/q/202895/173448), [Is it wrong to downvote a good answer to a duplicate question?](https://meta.stackoverflow.com/q/253735/608639), [Should there be a deterrent for answering obvious duplicate questions?](https://meta.stackoverflow.com/q/252009/608639), etc – jww Feb 22 '18 at 07:53
  • Like I said, the answer is not that good. It had been provided at least 9 other times in 3 previously asked questions. It would be a different story if there was some value added. But the best I can tell, its just an instance of the fastest gun in the west to get the points. – jww Feb 22 '18 at 07:55
  • 2
    Upvoting to offset unfair downvoting – Killzone Kid Feb 22 '18 at 07:58
  • @KillzoneKid - If you think this is a quality answer then you should check out some of the other answers at [Erasing vector::end from vector](https://stackoverflow.com/q/9590117/608639) and [std::remove with vector::erase and undefined behavior](https://stackoverflow.com/q/23761273/608639). They include the fastest gun in the west's answer, and discuss things like undefined behavior and the design decisions. In the end the question should have been close instead of fodder for rep whоring. – jww Feb 22 '18 at 08:30
13

vec.end() is giving you the iterator to the element following the last element of the container. See here:

enter image description here

Attempting to erase it is undefined behaviour. You should instead erase by doing either:

vec.erase(vec.end() - 1);

or better yet use pop back:

vec.pop_back();

 
Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
  • Should probably mention that if vector is empty the operation will crash, so to be on the safe side `if (!vec.empty()) vec.erase(vec.end() - 1);` – Killzone Kid Feb 22 '18 at 23:26
6

std::vector::end() returns an iterator that is one past the last element of the object. It is not valid for erasing. To remove the last element from a vector, you need to use the iterator that points to the last element.

You can use begin() + size - 1 for that.

size_t size = vec.size();
vec.erase(vec.begin() + size - 1);

Better yet, use std::vector::pop_back().

vec.pop_back();
R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

You need to erase the (vec.end - 1)th element, since vec.end is referring to the past-the-end element in the vector container.

1

To remove the last element of the vector, you can also use vector::pop_back() function.

For example:

#include <iostream> 
#include <vector> 
using namespace std; 

int main() 
{ 
    vector<int> myvector{ 1, 2, 3, 4, 5 }; 
    myvector.pop_back(); 

    // Vector becomes 1, 2, 3, 4 

    for (auto it = myvector.begin(); it != myvector.end(); ++it) 
        cout << ' ' << *it; 
} 

pop_back() is actively used in problems involving backtracking like finding all possible subsets of a given set. Hope it helps

sarthakgupta072
  • 451
  • 6
  • 13