Working anywhere in a vector
push_back adds an item at the end and pop_back removes the last one. To change the middle or the front of a vector, you need two methods that work on a position: insert and erase.
A position is not a plain number. v.begin() is the position of index 0, and v.begin() + i is the position of index i. This is why both calls below start from begin().
insert and erase
insert(pos, x) puts x at the position. Everything from that position on moves one place to the right. erase(pos) removes the item at the position, and everything after it moves one place to the left.
vector<string> colors = {"red", "green", "blue"};
colors.insert(colors.begin() + 1, "pink");
// colors is now {"red", "pink", "green", "blue"}
colors.erase(colors.begin());
// colors is now {"pink", "green", "blue"}
Printing the vector after each call shows exactly this: red pink green blue after the insert, then pink green blue after the erase.
The new item takes the index you chose. In the example, "pink" is at index 1, and "green", which was at index 1, is now at index 2. Inserting at v.end() works too, and has the same effect as push_back.
Common mistakes
- Passing a number.
erase(1)does not mean "erase index 1". The call needs a position, so writeerase(v.begin() + 1). - Forgetting that indexes shift. After an insert or an erase, every item behind that spot has a new index. If you insert at index 1 and then want the item that used to be at index 1, it is now at index 2.
- Going past the end. C++ does not check the position.
v.begin() + 10on a vector of three items is not an error you can rely on being reported: the program can crash or misbehave. Keep the index between 0 andv.size()forinsertand belowv.size()forerase.
The exercise: the vet's waiting line
pets starts as Rex, Milo, Luna. Bella has an appointment and goes second, at index 1. Then Milo leaves.
- Insert Bella at
pets.begin() + 1. Milo and Luna each move one place to the right, so the line is now Rex, Bella, Milo, Luna. - Milo is now at index 2, not index 1, because of the insert. Erase
pets.begin() + 2.
vector<string> pets = {"Rex", "Milo", "Luna"};
pets.insert(pets.begin() + 1, "Bella");
cout << pets.size() << endl;
pets.erase(pets.begin() + 2);
cout << pets[0] << " " << pets[1] << " " << pets[2] << endl;
The output is:
4
Rex Bella Luna
If you erased index 1 in step 2 by habit, Bella would be removed instead of Milo. The order of the two calls matters for the same reason.
Tracing the line
When an exercise changes a vector twice, write the vector down after each call. Starting from Rex, Milo, Luna: after the insert it is Rex, Bella, Milo, Luna with four items; after the erase it is Rex, Bella, Luna with three. The size grows by one with each insert and shrinks by one with each erase, which is a quick way to check your work: here the first cout prints 4 because it runs between the two calls.
The same habit helps with a safe index. Before you erase, ask whether the index is smaller than size(). Before you insert, ask whether it is at most size().
Key takeaways
v.begin() + iis the position of indexi.insert(pos, x)shifts the items fromposto the right;erase(pos)shifts the items afterposto the left.- Re-count the indexes after every insert or erase.
- Stay inside the vector: C++ does not check positions for you.
