C++: STL Container Basics
In previous lessons, we learned about templates — making functions and classes support any type.
But in real projects, you don't need to write your own containers (like dynamic arrays or linked lists).
The C++ Standard Template Library (STL) already provides ready-made containers — just use them directly!
1. What Is the STL?
The STL (Standard Template Library) is part of the C++ standard library, containing:
| Component | Purpose | Examples |
|---|---|---|
| Containers | Store data | std::vector, std::array |
| Iterators | Traverse containers | begin(), end() |
| Algorithms | Manipulate data | std::sort, std::find |
| Function objects | Custom comparison logic | std::less, std::greater |
💡 Key point: The STL is implemented with templates, so it supports any type.
2. vector (Most Commonly Used)
(1) 2.1 What Is vector?
std::vector is a dynamic array — its size can grow automatically.
| Comparison | Plain Array | vector |
|---|---|---|
| Size | Fixed | Dynamic |
| Memory | Stack or heap | Heap |
| Access elements | arr[i] |
vec[i] or vec.at(i) |
| Recommendation | ⭐⭐ | ⭐⭐⭐⭐⭐ |
▶ Example 1: vector Basic Usage (Difficulty ⭐)
#include <iostream>
#include <vector>
int main() {
// Create a vector storing ints
std::vector<int> vec = {1, 2, 3, 4, 5};
// Access elements
std::cout << "First element: " << vec[0] << std::endl;
std::cout << "Second element: " << vec.at(1) << std::endl;
// Modify elements
vec[0] = 100;
// Get size
std::cout << "Size: " << vec.size() << std::endl;
return 0;
}
Output:
First element: 1
Second element: 2
Size: 5
💡 Tip: vec.at(i) performs bounds checking and throws an exception if out of bounds; vec[i] does not check, and is more efficient.
(2) 2.2 Adding and Removing Elements
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec;
// Add elements to the end
vec.push_back(10);
vec.push_back(20);
vec.push_back(30);
// Remove the last element
vec.pop_back();
// Insert element at a specified position
vec.insert(vec.begin() + 1, 15); // Insert 15 at the second position
// Remove element at a specified position
vec.erase(vec.begin() + 1); // Remove the second element
return 0;
}
(3) 2.3 Traversing a vector
Method 1: Subscript traversal (most common)
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
for (size_t i = 0; i < vec.size(); i++) {
std::cout << vec[i] << " ";
}
std::cout << std::endl;
return 0;
}
Method 2: Range-based for (C++11, recommended)
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
for (int x : vec) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
Method 3: Iterators (covered later)
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
💡 Recommendation: Prefer range-based for (C++11) — it's the most concise.
3. array (Fixed-Size Array)
(1) 3.1 What Is array?
std::array is a fixed-size array, but safer than a plain array.
| Comparison | Plain Array | array |
|---|---|---|
| Size | You need to know it | Get with size() |
| Decays to pointer? | Yes | No |
| Recommendation | ⭐⭐ | ⭐⭐⭐⭐ |
▶ Example 2: array Basic Usage (Difficulty ⭐)
#include <iostream>
#include <array>
int main() {
// Create an array storing 5 ints
std::array<int, 5> arr = {1, 2, 3, 4, 5};
// Access elements
std::cout << "First element: " << arr[0] << std::endl;
// Get size
std::cout << "Size: " << arr.size() << std::endl;
return 0;
}
Output:
First element: 1
Size: 5
💡 Key point: The size of std::array is determined at compile time and cannot be changed.
4. deque (Double-Ended Queue)
(1) 4.1 What Is deque?
std::deque is a double-ended queue — you can quickly add/remove elements at both ends.
| Operation | vector | deque |
|---|---|---|
| Add at end | O(1) | O(1) |
| Add at front | O(n) | O(1) |
| Random access | O(1) | O(1) |
▶ Example 3: deque Basic Usage (Difficulty ⭐⭐)
#include <iostream>
#include <deque>
int main() {
std::deque<int> dq;
// Add at end
dq.push_back(10);
dq.push_back(20);
// Add at front
dq.push_front(5);
dq.push_front(1);
// dq is now: 1, 5, 10, 20
for (int x : dq) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
Output:
1 5 10 20
5. list (Doubly Linked List)
(1) 5.1 What Is list?
std::list is a doubly linked list — each element stores the addresses of the previous and next elements.
| Comparison | vector | list |
|---|---|---|
| Random access | O(1) | ❌ Not supported |
| Insert/delete in middle | O(n) | O(1) |
| Memory usage | Small | Large (two extra pointers per element) |
▶ Example 4: list Basic Usage (Difficulty ⭐⭐)
#include <iostream>
#include <list>
int main() {
std::list<int> lst = {1, 2, 3, 4, 5};
// Add at front
lst.push_front(0);
// Add at end
lst.push_back(6);
// Remove elements with value 3
lst.remove(3);
for (int x : lst) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
Output:
0 1 2 4 5 6
6. forward_list (Singly Linked List)
(1) 6.1 What Is forward_list?
std::forward_list is a singly linked list — each element only stores the address of the next element.
| Comparison | list | forward_list |
|---|---|---|
| Memory usage | Larger | Smaller |
| Can traverse backwards? | ✅ | ❌ |
| Recommendation | ⭐⭐⭐⭐ | ⭐⭐ (for specific scenarios) |
💡 Advice: Unless you're certain you only need forward traversal, use std::list.
7. Container Selection Guide
| Scenario | Recommended Container |
|---|---|
| Need dynamic size | std::vector |
| Fixed size, want C-style compatibility | std::array |
| Need fast add/remove at front | std::deque |
| Frequent insert/delete in the middle | std::list |
| Only need forward traversal and want to save memory | std::forward_list |
💡 Golden rule: Prefer std::vector unless you have a clear reason to use something else.
8. Practice: Dynamic Array with vector (Difficulty ⭐⭐)
#include <iostream>
#include <vector>
#include <string>
struct Student {
std::string name;
int age;
double score;
};
int main() {
std::vector<Student> students;
// Add students
students.push_back({"Alice", 20, 92.5});
students.push_back({"Bob", 21, 88.0});
students.push_back({"Charlie", 19, 95.0});
// Traverse and output
for (const auto& s : students) {
std::cout << "Name: " << s.name
<< ", Age: " << s.age
<< ", Score: " << s.score << std::endl;
}
return 0;
}
❓ FAQ
Q: What's the difference between vector and array? A:> -
vectorhas dynamic size, stored on the heap > -arrayhas fixed size, stored on the stack > > Selection advice: If the size is uncertain, usevector; if the size is fixed and small, usearray. Q: Why is range-based for recommended for traversing vector? A: Because it's more concise and less prone to loop condition errors. > > // Traditional for (easy to get conditions wrong) > for (size_t i = 0; i < vec.size(); i++) { ... } > > // Range-based for (concise, less error-prone) > for (int x : vec) { ... } > Q: Which is faster — list or vector? A: It depends on the scenario: > - If you need random access (vec[100]),vectoris faster > - If you need frequent insert/delete in the middle,listis faster
Q: What's the most important thing about STL containers? A: Understand the core concepts first, then reinforce them through practical examples.
📖 Summary
- STL containers are ready-made data structures provided by the C++ standard library
- vector is the most commonly used (dynamic array)
- array is for fixed-size scenarios
- deque supports fast operations at both ends
- list is a doubly linked list, good for frequent insert/delete
- Prefer vector unless you have a clear reason to use something else
📝 Exercises
-
Basic (Difficulty ⭐): Use
std::vector<int>to store 5 integers, traverse and output them. -
Intermediate (Difficulty ⭐⭐): Use
std::vector<std::string>to store 3 strings, let the user input them, then output. -
Challenge (Difficulty ⭐⭐⭐): Use
std::dequeto implement "palindrome detection": -
Compare from both ends toward the middle; if all corresponding characters match, it's a palindrome
-
Example:
"racecar"is a palindrome,"hello"is not
- STL container categories: sequential (vector/list/deque) and associative (set/map)
- vector dynamic array: fast add/remove at end, supports random access
- list doubly linked list: fast insertion at any position
- map key-value container: sorted by key, lookup O(log n)
- set set container: unique elements, automatically sorted
9. 🚀 Next Steps
Now that you've learned STL container basics, next we'll study STL Algorithms (lesson 35) — using the algorithms provided by the standard library to manipulate containers, so you don't have to write your own sorting, searching...