Module 0 ¡ What the STL Is, and Why It Changes How You Write C++
The STL in One Picture: Four Kinds of Thing
In this lesson
- Say what the STL is in one sentence.
- Name its four kinds of thing and give one example of each.
- Explain what the STL is not, so you know where to look for the rest.
Maria has a C program that keeps a shop's price list. It has a hand-written growing array, a hand-written linked list and a hand-written sort. It is about 300 lines long, and it has two bugs she has not found yet.
The same program in C++ with the STL is about 40 lines. The two bugs are gone. Nobody fixed them: the lines that held them no longer exist, because the growing array, the list and the sort now come from the library.
Maria asks the question this whole module answers: "But why should I trust code I did not write?" Before we answer it, you need the map. This lesson is the map.
What the STL is, in one sentence
The STL (Standard Template Library) is the part of the C++ standard library that provides containers, iterators, algorithms and function objects, built to fit together.
The standard library is the code that ships with every C++ compiler, the way printf and qsort ship with every C compiler. You do not download it. You include a header and use it.
The design came from Alexander Stepanov, working with Meng Lee at Hewlett-Packard. The C++ standards committee voted it into the draft standard in 1994. It has been part of every C++ standard since the first one, C++98. The word "Template" in the name means the same code works for any type of element. Module 1 shows you what that means in practice.
So the STL is not a separate product. It is a set of headers, such as <vector> and <algorithm>, that your compiler already has.
The picture: four kinds of thing
Everything in this track belongs to one of four kinds. Learn this picture now. Every later module adds detail to one of its boxes, and you will see it again at the top of each one.
Read the arrows from left to right. A container hands out iterators. Two iterators mark a stretch of elements, called a range. An algorithm works on that range, and a function object, when you pass one, tells the algorithm how to compare or what to do.
So the four kinds are not four piles of features. They are four parts of one machine, and the iterator is the part in the middle that lets the other three meet.
Reading one STL line
std::sort(prices.begin(), prices.end(), std::greater<int>());
std::says the name comes from the standard library. Every STL name lives there.sortis the algorithm, the work to be done.pricesis the container, the thing holding the numbers.prices.begin()andprices.end()are two iterators: where the range starts, and just past where it stops.std::greater<int>()is a function object: "put the bigger one first".
Containers hold things
A container is an object that holds a collection of elements and manages their memory for you. You add to it and remove from it. It grows and shrinks on its own, so you never call malloc or free for it.
std::vector is the one you will use most. It is a growing array: the elements sit next to each other in memory, just like a C array, and you can still write v[0].
The smallest useful STL program. Three scores go in, and the vector keeps count.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> scores;
scores.push_back(72);
scores.push_back(45);
scores.push_back(90);
std::cout << "I hold " << scores.size() << " scores\n";
std::cout << "The first is " << scores[0] << '\n';
}
I hold 3 scores
The first is 72
push_back adds one element at the end, and size() says how many there are. There is no capacity to track and nothing to free. If std::cout << is new to you, read it as printf for now; Module 1 teaches it properly.
Iterators point into containers
An iterator is an object that points at one element of a container and can move to the next one. If you know C pointers, you already know the idea: *it reads the element it points at, and ++it moves it forward.
Every container hands out two of them. begin() points at the first element. end() points one step past the last element, a position with nothing in it. Lesson 4 explains why that is the right choice.
The long type name is written out once so you can see it. From Module 1 on, auto writes it for you.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> scores = {72, 45, 90};
std::vector<int>::iterator it = scores.begin();
std::cout << *it << '\n';
++it;
std::cout << *it << '\n';
}
72
45
The iterator started at 72, moved one step, and then read 45. So an iterator is a position you can read and move, which is exactly what a pointer into a C array is.
Run in CompilerAlgorithms work through iterators
An algorithm is a function template in <algorithm> (or <numeric>) that does one job on a range: sort it, search it, count in it, reverse it. There are more than a hundred of them.
Here is the important part. An algorithm takes two iterators, not a container. It never asks "is this a vector?". It only walks from the first iterator to the second. That is why one std::sort works on a vector, on a plain array and on containers that were written years after it.
Two algorithms on one vector: std::sort puts it in order, and std::count counts one value.
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> scores = {72, 45, 90, 45, 61};
std::sort(scores.begin(), scores.end());
std::cout << "sorted:";
for (int s : scores) std::cout << ' ' << s;
std::cout << '\n';
std::cout << "45 appears " << std::count(scores.begin(), scores.end(), 45) << " times\n";
}
sorted: 45 45 61 72 90
45 appears 2 times
The line for (int s : scores) means "for each element s of scores". It is the range-for, and Module 1 gives it a lesson of its own. Notice that neither algorithm was told the size: the two iterators carry that.
Function objects tell an algorithm how
A function object (also called a functor) is anything you can call like a function. You pass one to an algorithm to change how it does its job. std::sort puts the smaller element first by default; give it std::greater<int>() and it puts the bigger one first.
In C you did the same thing with a function pointer, the comparator you pass to qsort. A function object does that job, with the type checked by the compiler. The most common kind today is a lambda, a small function written right where you need it. Module 12 teaches lambdas; here you only need to recognise one.
The same sort, twice. The second call gets a function object, and the order flips.
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> scores = {72, 45, 90, 61};
std::sort(scores.begin(), scores.end());
std::cout << "smallest first: " << scores[0] << '\n';
std::sort(scores.begin(), scores.end(), std::greater<int>());
std::cout << "biggest first: " << scores[0] << '\n';
}
smallest first: 45
biggest first: 90
std::greater<int> lives in <functional>. It answers one question for any two ints: "is the first one bigger?". So the sort did not change; only the rule it compares with did.
All four in one program
Here is the core of Maria's rewrite: her price list, sorted from the most expensive down, with the top three printed. Point at each line and name its kind before you read the note under it.
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> prices = {450, 1200, 80, 990, 300, 640};
std::sort(prices.begin(), prices.end(), std::greater<int>());
std::cout << "Top three prices:\n";
for (auto it = prices.begin(); it != prices.begin() + 3; ++it) {
std::cout << " " << *it << '\n';
}
std::cout << "Items over 500: "
<< std::count_if(prices.begin(), prices.end(), [](int p) { return p > 500; }) << '\n';
}
Top three prices:
1200
990
640
Items over 500: 3
The vector is the container. sort and count_if are algorithms. begin() and it are iterators, and begin() + 3 is "three steps in". std::greater<int>() and the lambda [](int p) { return p > 500; } are function objects. Fifteen lines of code, and not one of them manages memory.
What the STL is not
Knowing the edges saves you a long search. Three things people expect to find in the STL are not there.
- Not a GUI library. There are no windows, buttons or images. Programs with a window use a separate library such as Qt.
- Not a network library. Standard C++17 and C++20 have no sockets and no HTTP. A server uses the operating system's calls or a library such as Boost.Asio.
- Not the whole standard library. Input and output (
<iostream>), time (<chrono>), threads and files are standard library too. They are not the container, iterator and algorithm design this track is about.
One honest note on the name. Many programmers say "the STL" when they mean the whole standard library, and you will hear it used both ways. This track uses it for the four kinds above, plus std::string, which behaves like a container of characters.
Where this is used
- LLVM. The compiler toolkit behind Clang uses
std::vectorandstd::sortthroughout. It also has its own containers, such asSmallVector, built with the samebegin()andend(), so the standard algorithms work on them unchanged. - Chromium. The browser behind Chrome and Edge uses the standard containers. Where it needed something different, its
baselibrary adds containers such asbase::flat_mapwith the same iterator interface. - Unreal Engine, the counter-example. The game engine ships its own containers (
TArray,TMap,TSet) and its code uses them instead of the STL's. Even so, aTArrayhasbegin()andend(), so the four-kinds picture still describes it. - Programming contests. ICPC and Codeforces compile C++ with the full standard library. A contestant sorts a million numbers with one call to
std::sortand spends the saved time on the problem.
Common mistakes
1. Looking for sort on the container.
std::vector<int> v = {3, 1, 2};
v.sort();
GCC 12 says error: 'class std::vector<int>' has no member named 'sort'. Algorithms are not members of the container; they stand apart and take iterators. Write std::sort(v.begin(), v.end());. You will make this mistake because most languages you meet later put sort on the list itself.
2. Forgetting the algorithm's header.
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {3, 1, 2};
std::sort(v.begin(), v.end());
}
On the Playground, GCC 12 says error: 'sort' is not a member of 'std'; did you mean 'qsort'?. Containers have their own headers, and algorithms live in <algorithm>. Add #include <algorithm>. Some other compilers happen to compile this anyway, which is why it surprises people when it stops working.
3. Choosing the container before knowing the question.
Kenji's first question is always "which container is fastest?". No container is fastest at everything: one is fast at adding to the end, another at finding a name, another at keeping things in order. Lesson 3 is the table that answers "fastest at what?". Decide what you will ask of the data first, then pick.
Sort these eight names into the four kinds: std::vector, std::find, begin(), std::greater<int>, std::map, std::reverse, end(), std::less<int>.
Check yourself. You should have two names in each kind. If one box has three, look again at Figure 1 and at the syntax card above.
Maria's C program had three hand-written parts: a growing array, a linked list and a sort. For each one, write the STL name that replaces it and the kind it belongs to.
Rules. One line per part. You may use Lesson 3's container list if you have read it; otherwise, guess the list's name from its job and check it later.
Check yourself. Two of your three answers are containers and one is an algorithm. The algorithm needs a container to work on, but not a particular one.
Write one paragraph that answers this: std::sort was written more than ten years before LLVM's SmallVector existed, yet it sorts a SmallVector correctly. How can a function work on a container its author never saw?
Rules. Use the words "iterator" and "range". Do not use the word "magic".
Check yourself. A good answer says that sort never sees the container, only two iterators. Any container that hands out the right kind of iterator can be sorted. Figure 1's dashed box is the whole answer.
Common doubts
Is the STL a separate thing I have to install?
No. It is part of the standard library that comes with every C++ compiler, including the Playground's GCC 12. You include a header such as
<vector>and it is there.Do I need to know C++ classes before learning the STL?
No. You need to use classes, not write them, and using one looks like
v.push_back(3). Module 1 teaches the few C++ pieces this track relies on. Writing your own classes and templates belongs to a C++ track.Is code that uses the STL slower than hand-written C?
Usually not, and sometimes faster:
std::sortis often faster thanqsort, because the compiler can inline the comparison. Lesson 2 is honest about where the STL does cost you something.Why is it called a "template" library?
Because each container and algorithm is written once as a template, a pattern the compiler fills in with your type.
std::vector<int>andstd::vector<double>are two versions it writes for you. Module 1 has a lesson on this idea.
Key takeaways
- The STL is the part of the C++ standard library that gives containers, iterators, algorithms and function objects.
- Containers hold, iterators point, algorithms work, function objects say how.
- An algorithm takes two iterators, never a container, so one algorithm works on many containers.
- The STL is not a GUI, not a network library and not the whole standard library.
- Figure 1 is the map: every later module fills in one of its boxes.
Next you will see why it is worth learning. Three programs are written twice, once in C and once with the STL, beside the costs nobody puts on the poster.
End of lesson 1
Mark it done, and your progress moves with you.
Next: Why It Matters: Fewer Lines, Fewer Bugs, Known Costs