2

Why does using vector.erase(vector.end()) produces a

Segmentation fault (core dumped)

when using this code:

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

void printMe(vector<int>& v){ for(auto &i:v) cout<<i<<" "; cout<<"\n"; }

int main() {
    vector<int> c = { 1,2,3,4,5,6,7,8};
    printMe(c);
    c.erase(c.begin());
    printMe(c);
    c.erase(c.begin());
    printMe(c);
    // c.erase(c.end()); //will produce segmentation fault
    // printMe(c);
    return 0;
}

I'm a bit new to these iterators , so this caught me off guard. While I know there exists vector.pop_back(). I'm curious to know what exactly causes this.

A link to the program.

NAND
  • 663
  • 8
  • 22
Abhinav Gauniyal
  • 7,034
  • 7
  • 50
  • 93
  • 5
    `vector.end()` is the past-the-end iterator. It doesn't point to an element that can be erased. – T.C. Apr 09 '15 at 05:09
  • @T.C. now I'm curious why is .end() pointing to past-the-end , any use-cases? because end generally refers to last element , as I'm getting from begin-> pointing to 1st element. – Abhinav Gauniyal Apr 09 '15 at 05:11
  • 5
    http://stackoverflow.com/questions/9963401/why-are-standard-iterator-ranges-begin-end-instead-of-begin-end – user657267 Apr 09 '15 at 05:15
  • 3
    Because C++'s convention is that ranges are half-open: `[begin, end)`. – T.C. Apr 09 '15 at 05:16
  • 2
    Begin is where you begin, with the first element. End is where you end, when you've past the last element. (You may want `rbegin`, which is where the sequence of elements in reversed order begins, which is with the last element.) If `begin` was the first element and `end` was the last element, how would an insert function work? If it inserts after the specified iterator, you can't put something at the beginning. If it inserts before, you can't put something at the end. – David Schwartz Apr 09 '15 at 05:16
  • 3
    @DavidSchwartz , I got it :) also for empty ranges, begin() will be equal to end() , which makes sense. – Abhinav Gauniyal Apr 09 '15 at 05:24

4 Answers4

5

vector::end() does not point to the last element, it points to the element just after the last element.

Quoting cplusplus.com,

std::vector::end

Returns an iterator referring to the past-the-end element in the vector container.

The past-the-end element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced.

Because the ranges used by functions of the standard library do not include the element pointed by their closing iterator, this function is often used in combination with vector::begin to specify a range including all the elements in the container.

Hence, it has nothing to erase() there, and hence the error.


Replace

c.erase(c.end());

with

c.erase(c.end() - 1);
shauryachats
  • 9,975
  • 4
  • 35
  • 48
  • There's no overload of `erase` that takes a `reverse_iterator`. `std::reverse_iterator` does allow you to recover the underlying iterator with `.base()`, but `rbegin().base()` is just `end()`, so we are back where we started. – T.C. Apr 09 '15 at 05:23
  • @T.C. You are right, I have removed the `reverse_iterator` part. As, we still have to use `.base()` to convert reverse iterator to forward iterator, which is of no productive use. – shauryachats Apr 09 '15 at 05:26
0

vector::end() points to one after the last element.

Therefore it does not point to an element.

Thus, there is nothing to delete.

If you wish to delete the last element, you need to delete the element before that, as you do in your ideone link.

danielschemmel
  • 10,885
  • 1
  • 36
  • 58
0

Vector's end() returns an iterator referring to the element which should be AFTER the last element in container.

So you are trying to erase the memory which does not belong to you, this produces SIGSEGV (11).

pstanisz
  • 181
  • 9
-1

As volerag mentioned above just replace c.erase(c.end()); with c.erase(c.end()-1);

deanone
  • 109
  • 1
  • 3