The list Container
The standard containers share operation notation, so the same name is written the same way across containers such as vector and list.
Carrying Vocabulary from One Container to Another
Suppose you already know how to add an element to the end of one kind of container, and now you need to use a different kind. Do you have to learn a completely new vocabulary for the second one, or does the vocabulary carry over? The standard library answers this question in a specific way, and the answer shapes how you read almost any container code you meet.
The short answer is that the vocabulary carries over. The standard containers, such as vector and list, are built so that their basic operations look alike when you write them down. A call that works on one container is written with the same name and the same shape of syntax on another, so you can read the code without first checking which container you are looking at. This shared notation is deliberate.
Shared Names and Shared Meanings
The standard containers share operation notation, so the same name is written the same way across containers such as vector and list. Sharing a notation is, however, only half of the design. The meaning of each shared operation is also equivalent across containers.
An operation named for finding the start of a sequence means the start of the sequence whether the container underneath is a vector, a list, or another container type. What differs between containers lies in how each one stores its elements, not in what the basic operations are supposed to mean. So when you see begin(), push_back(), size(), or end(), you can rely on the idea behind the name even before you know the container's internal layout.
Reading begin() and end() as Boundaries
begin() and end() are best read together. begin() gives an iterator to the first element, and end() gives an iterator to the position one beyond the last element. Together they mark the boundaries of the whole sequence: the first position you can visit, and the position where a walk through the elements stops.
Notice that end() is not an element you can read. It is a marker that sits past the final element. Because it works as a stopping point for a walk through the container, it is described as one-beyond-the-last rather than as the last element. Picture the elements as a row of slots: begin() points at the first slot, and end() points at the empty slot just after the final one.
Tracing push_back() and size() Step by Step
push_back() adds an element to the end of a container, and size() returns the number of elements. Together these two operations let you watch a container change. Each push_back() call grows the container by one element at its end, and size() reports the new count afterward.
0
3- 1The container starts empty, so
size()reports 0. - 2Each
push_backcall adds one element at the end, in the order the calls are made. - 3After three calls the container holds 10, 20, and 30, and
size()describes that count as 3.
- std::list<int> scores creates an empty container of integers
size()reports 0 before anything is addedpush_back(30)places the third element after the existing onessize()reports 3 after the three additions
scores holds: 10, 20, 30Three elements, size() reports 3
scores.push_back(40); scores holds: 10, 20, 30, 40Four elements, size() reports 4
What do you think happens?
If the container holds 10, 20, 30 and you call push_back(40), where does 40 appear, and what does size() report afterward?
Reveal answer
40 appears at the end and size() reports 4
push_back() adds an element to the end of the container, so the existing elements keep their order and the new one follows them. size() returns the number of elements, which goes from 3 to 4.
When a Shared Operation Applies
Uniformity has conditions. An operation applies where it makes sense and can be efficiently implemented. This means that a shared name does not guarantee identical cost everywhere. The name tells you what the operation is meant to do; it does not promise that every container will do it at the same price.
Read this way, the conditions for a basic operation come down to two questions. First, does the operation make sense for this container? Second, can it be implemented efficiently for this container? When both answers are yes, the call reads the same as it would on any other standard container. When either answer is no, the shared name still tells you the intended meaning, but you should not assume the operation is equally suited to that container.
Mistakes Readers Make With Shared Operations
Common mistake Treating end() as the last element
What it looks likeReading the value at end() and expecting the final element of the container
Why it failsend()marks the position one beyond the last element, so it is a stopping marker rather than a stored element.Do this insteadUse begin() as the first position and end() as the stopping point for a walk through the elements.
Common mistake Assuming a shared name means identical cost
What it looks likeChoosing a container only because the same operation name appears in both
Why it failsA shared name guarantees the meaning, but uniformity has conditions and an operation is not guaranteed to be efficient on every container.
Do this insteadCheck whether the operation is expected to apply efficiently to the specific container before relying on it.
Common mistake Expecting push_back() to insert at the front
What it looks likeCalling push_back(40) and assuming 40 becomes the first element
Why it failspush_back()adds an element to the end of the container.Do this insteadRead push_back() as appending after the current final element.
Common mistake Assuming the internal storage is shared when only the names are shared
Practice Reading a Container's Operations
A list container holds the values 5, 8, and 12 in that order. Predict what begin() points to, what end() points past, and what size() reports after one more push_back(7) call. Explain why end() does not hold a value.
Hints
begin()points to the first element, which is 5.end()points one position past the last element that exists at the time you ask.- After
push_back(7), the new element is last and the count increases by one.
Key Takeaways
- The standard containers share operation names and notation, so a call written for one container reads the same way on another.
- The shared names also carry equivalent meanings:
begin()gives the first element,end()gives the position one beyond the last element,push_back()adds at the end, andsize()returns the number of elements. end()is a marker, not a stored element, which is why it is read as one-beyond-the-last.- A shared name does not guarantee identical cost; a basic operation applies where it makes sense and can be efficiently implemented.