Container Operations: push_back() and erase()
push_back() is called on the container and appends a new element at the end.
A Task That Seems to Need a Different Size
Suppose you have a list of numbers and you want to replace every occurrence of one value with another. Or suppose you want to sort the numbers into order. Neither task obviously requires a different number of elements. Replacing a value leaves the count alone, and sorting rearranges the values that are already there. Now suppose instead that you want to add a new number to the end of the list, or remove a number from the middle. These tasks clearly change how many elements are stored. The question this article answers is how a program tells these two kinds of work apart, and which operation is responsible for each.
The source material frames the problem with a simple observation: it is tempting to think that an algorithm can grow or shrink a container whenever its task seems to call for it. The answer is that changing what is stored and changing how many elements are stored are different jobs. The key question is whether an operation works with a sequence of elements or with the container that holds them.
What do you think happens?
Start with v holding the values 1, 2, 3. You call replace(v.begin(), v.end(), 2, 9). What is v.size() afterward?
Reveal answer
3
replace() changes the value 2 to 9 in an existing position. It does not add or remove any element, so the size stays at 3. The array now holds 1, 9, 3.
Values Versus the Container
Two different kinds of work happen to a container. The first kind changes the values stored in positions that already exist. The second kind changes how many positions exist. Algorithms such as replace() and sort() belong to the first kind. The summary of the source material states that these algorithms can change element values without changing the number of elements.
The source explains that the distinction matters whenever an operation's result seems to require a different number of elements. If the task is to change values, an algorithm such as replace() or sort() may be suitable. If the task is to add or remove elements, the operation must also have a way to act on the container itself.
Read the diagram as a list of slots. The replace() operation finds the slot that holds the value 2 and writes 9 into that same slot. The other slots are not touched, and no slot is added or removed. This is why the number of slots is the same before and after. The algorithm changed what is stored, not how much is stored.
Why a Sequence Cannot Resize Its Container
An algorithm such as replace() or sort() receives a sequence, usually described by a range of positions from a starting point up to an ending point. A sequence does not identify the container that holds its elements. The algorithm can read and write the positions it has been given, but it has no handle on the container object itself. Without that handle, the algorithm has no way to add a new slot at the end or to close a gap in the middle.
The source describes this as a missing connection. Think of the back_inserter as the connection between an algorithm and the container that should grow. Without a way to refer to the container, the sequence alone does not tell the algorithm where added elements belong. The sequence tells the algorithm which values to read and where to write, but not where a new element should go once the existing positions are full.
Tracing replace() on a Vector
Changing a value without changing the size
A container named v holds the values 1, 2, 3. Use replace() to change the value 2 to 9, then confirm whether the size of the container has changed.
- 1Start with the initial state
The container holds three elements: 1 at index 0, 2 at index 1, and 3 at index 2. Its size is 3.
- 2Pass a sequence to replace()
The algorithm receives the range from the first position to the position just past the last one. It searches that range for the value 2.
- 3Write the new value into the matching position
The value 2 is found at index 1, so that position is overwritten with 9. No other position is written.
- 4Check the size
No element was added or removed. The container still has three positions, now holding 1, 9, and 3.
The values changed, but the size stayed at 3. This is the behavior the source attributes to algorithms such as replace() that change element values without changing the number of elements.
3
1 9 3 v.begin()andv.end()form the sequence passed to the algorithm.replace()writes 9 into the one matching position.- The size printed afterward is still 3.
The example uses the C++ standard library names for these operations. The same idea holds in any setting where an algorithm is given a range of positions: the operation rewrites values inside that range and leaves the number of positions to whoever owns the container.
Growing and Shrinking the Container Directly
When the task is to add or remove elements, the operation must act on the container itself. The source names two direct container operations for this purpose: push_back() for adding an element and erase() for removing one. Each is called on the container, so it has the handle that the sequence alone lacks.
Because these operations change the container, they change how many elements it holds. This is the second kind of work described earlier. The rule of thumb from the source is simple: use direct container operations such as push_back() or erase() when adding or removing elements directly.
Connecting Algorithms with back_inserter
Sometimes an algorithm does produce output that must be stored in a container that grows. The source gives the rule: use a back_inserter to connect an algorithm to a container when adding elements. The back_inserter supplies the missing link. It refers to the container, so each value the algorithm produces can be added to the end of that container.
- std::
back_inserter(dest)names the container that should grow. - Each value written by std::copy is appended to dest.
- dest starts empty and ends with three elements.
The back_inserter is needed here because an ordinary destination sequence cannot grow on its own. Without a reference to dest, the copying algorithm would have nowhere to place the new values beyond the positions that already exist.
Mistakes Beginners Make with Size and Values
Common mistake Expecting replace() or sort() to add or remove elements
What it looks likeCalling replace() on a container of three values and assuming it now holds four.
Why it failsThese algorithms change element values without changing the number of elements. The size stays the same.
Do this insteadIf the count must change, call push_back() or erase() on the container, or use a back_inserter when an algorithm must write into a growing container.
Common mistake Treating a sequence as if it identifies the container
What it looks likePassing only a begin and end position to an algorithm and expecting it to append values somewhere.
Why it failsA sequence does not identify the container that holds its elements, so the algorithm cannot grow that container.
Do this insteadGive the algorithm a back_inserter that refers to the container, or perform the add operation on the container directly.
Common mistake Calling push_back() when the goal is to overwrite a value
What it looks likeUsing push_back(9) to change the 2 in the list 1, 2, 3 to 9.
Why it failspush_back()appends a new element. It does not replace the value already in a position, so the container grows instead.Do this insteadUse an operation that changes values in existing positions, such as replace() for matching values.
Choosing Between an Algorithm, back_inserter, and Direct Operations
| Goal | Suitable approach | Effect on the number of elements |
|---|---|---|
| Change matching values in place | replace() | Unchanged |
| Rearrange existing values into order | sort() | Unchanged |
| Add elements from an algorithm's output | Algorithm connected through a back_inserter | Increases as values are written |
| Add one element at the end | push_back() on the container | Increases by one |
| Remove one element | erase() on the container | Decreases by one |
Matching the task to the operation that owns the change
A useful test is to ask whether the result needs a different number of elements. If the answer is no, an algorithm that changes values, such as replace() or sort(), may be suitable. If the answer is yes, the operation must reach the container itself, either by calling push_back() or erase() directly, or by connecting an algorithm to the container through a back_inserter.
Practice: Classifying Operations by Effect
A container holds the values 5, 7, 7, 2. For each task below, decide whether the operation changes only values, or whether it changes the number of elements, and name the operation you would use. (a) Change every 7 to 8. (b) Add the value 1 to the end. (c) Remove the element at index 0. (d) Sort the values into ascending order.
Hints
- Ask first whether the number of elements must change.
- Operations that overwrite or rearrange existing positions leave the size unchanged.
push_back()anderase()are called on the container and change its size.
Key Takeaways for Container Operations
- Algorithms such as
replace()andsort()can change element values without changing the number of elements. - A sequence does not identify the container that holds its elements, so an algorithm working only on a sequence cannot grow or shrink that container.
- Use direct container operations such as
push_back()orerase()when adding or removing elements directly. - Use a
back_inserterto connect an algorithm to a container when the algorithm must add elements.
At a glance
- Changing what is stored and changing how many elements are stored are different jobs.
replace()andsort()change values or order within existing positions, so the size stays the same.push_back()anderase()are called on the container and change its number of elements.- A
back_inserterconnects an algorithm to the container that should grow when the algorithm adds elements.