40% complete
C++ Standard Template Library (STL)
The Standard Template Library (STL) is a powerful set of C++ template classes to provide general-purpose classes and functions with templates that implement many popular and commonly used algorithms and data structures like vectors, lists, queues, and stacks.
What You'll Learn
- STL containers for storing collections of objects
- STL algorithms for processing data
- STL iterators for traversing containers
- STL function objects (functors) for customizing algorithms
- STL adaptors for modifying interfaces
Introduction to the STL
The Standard Template Library (STL) is organized into three primary components:
- Containers: Objects that store collections of other objects
- Algorithms: Functions for processing sequences of elements
- Iterators: Objects that connect algorithms to containers
The STL provides a set of common classes for easy and efficient implementation of common data structures and algorithms. It is built on template classes, allowing it to work with any data type while maintaining type safety and performance.
STL Containers
Containers are objects that store collections of other objects (elements). The STL provides several types of containers:
Sequence Containers
These containers store elements in a linear sequence:
1#include <iostream>2#include <vector>3#include <list>4#include <deque>5using namespace std;67int main() {8 // Vector - Dynamic array9 vector<int> vec = {1, 2, 3, 4, 5};10 vec.push_back(6); // Add element at the end1112 cout << "Vector elements: ";13 for (int num : vec) {14 cout << num << " "; // Output: 1 2 3 4 5 615 }16 cout << endl;1718 // List - Doubly linked list19 list<string> lst = {"Apple", "Banana", "Cherry"};20 lst.push_front("Avocado"); // Add at the beginning21 lst.push_back("Date"); // Add at the end2223 cout << "List elements: ";24 for (const string& fruit : lst) {25 cout << fruit << " "; // Output: Avocado Apple Banana Cherry Date26 }27 cout << endl;2829 // Deque - Double-ended queue30 deque<float> dq = {1.1, 2.2, 3.3};31 dq.push_front(0.0); // Add at the beginning32 dq.push_back(4.4); // Add at the end3334 cout << "Deque elements: ";35 for (float val : dq) {36 cout << val << " "; // Output: 0 1.1 2.2 3.3 4.437 }38 cout << endl;3940 return 0;41}
Associative Containers
These containers implement sorted data structures:
1#include <iostream>2#include <set>3#include <map>4using namespace std;56int main() {7 // Set - Collection of unique keys, sorted by keys8 set<int> numSet = {5, 2, 8, 5, 1, 3}; // Duplicate 5 will be ignored9 numSet.insert(7);1011 cout << "Set elements: ";12 for (int num : numSet) {13 cout << num << " "; // Output: 1 2 3 5 7 8 (sorted)14 }15 cout << endl;1617 // Map - Collection of key-value pairs, sorted by keys18 map<string, int> ages;19 ages["Alice"] = 30;20 ages["Bob"] = 25;21 ages["Charlie"] = 35;2223 cout << "Map elements: " << endl;24 for (const auto& pair : ages) {25 cout << pair.first << ": " << pair.second << endl;26 }27 // Output:28 // Alice: 3029 // Bob: 2530 // Charlie: 353132 return 0;33}
Unordered Associative Containers
These containers implement unsorted (hash table) data structures:
1#include <iostream>2#include <unordered_set>3#include <unordered_map>4using namespace std;56int main() {7 // Unordered Set - Collection of unique keys, hashed by keys8 unordered_set<int> hashSet = {5, 2, 8, 5, 1, 3}; // Duplicate 5 will be ignored9 hashSet.insert(7);1011 cout << "Unordered Set elements: ";12 for (int num : hashSet) {13 cout << num << " "; // Output: elements in no particular order14 }15 cout << endl;1617 // Unordered Map - Collection of key-value pairs, hashed by keys18 unordered_map<string, int> hashMap;19 hashMap["Alice"] = 30;20 hashMap["Bob"] = 25;21 hashMap["Charlie"] = 35;2223 cout << "Unordered Map elements: " << endl;24 for (const auto& pair : hashMap) {25 cout << pair.first << ": " << pair.second << endl;26 }27 // Output: elements in no particular order2829 return 0;30}
Container Adaptors
These are interfaces built on top of other containers:
1#include <iostream>2#include <stack>3#include <queue>4#include <priority_queue>5using namespace std;67int main() {8 // Stack - LIFO (Last-In-First-Out)9 stack<int> s;10 s.push(1);11 s.push(2);12 s.push(3);1314 cout << "Stack elements (popping): ";15 while (!s.empty()) {16 cout << s.top() << " "; // Output: 3 2 117 s.pop();18 }19 cout << endl;2021 // Queue - FIFO (First-In-First-Out)22 queue<int> q;23 q.push(1);24 q.push(2);25 q.push(3);2627 cout << "Queue elements (popping): ";28 while (!q.empty()) {29 cout << q.front() << " "; // Output: 1 2 330 q.pop();31 }32 cout << endl;3334 // Priority Queue - Highest priority element is always at the front35 priority_queue<int> pq; // Max heap by default36 pq.push(3);37 pq.push(1);38 pq.push(5);39 pq.push(2);4041 cout << "Priority Queue elements (popping): ";42 while (!pq.empty()) {43 cout << pq.top() << " "; // Output: 5 3 2 144 pq.pop();45 }46 cout << endl;4748 return 0;49}
STL Iterators
Iterators are objects that behave like pointers, used to access elements in containers. They provide a common interface for algorithms to work with different containers.
1#include <iostream>2#include <vector>3#include <list>4#include <algorithm> // For find()5using namespace std;67int main() {8 vector<int> vec = {10, 20, 30, 40, 50};910 // Different ways to iterate through a container1112 // 1. Using iterator objects13 cout << "Using iterators: ";14 for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {15 cout << *it << " ";16 }17 cout << endl;1819 // 2. Using auto for iterators (C++11)20 cout << "Using auto iterators: ";21 for (auto it = vec.begin(); it != vec.end(); ++it) {22 cout << *it << " ";23 }24 cout << endl;2526 // 3. Using range-based for loop (C++11)27 cout << "Using range-based for loop: ";28 for (int val : vec) {29 cout << val << " ";30 }31 cout << endl;3233 // Finding an element using algorithm and iterators34 auto it = find(vec.begin(), vec.end(), 30);35 if (it != vec.end()) {36 cout << "Found " << *it << " at position: "37 << distance(vec.begin(), it) << endl;38 } else {39 cout << "Element not found" << endl;40 }4142 return 0;43}
Iterator Categories
The STL defines several categories of iterators with different capabilities:
- Input iterators: Can read, cannot write, single pass (e.g., istream_iterator)
- Output iterators: Can write, cannot read, single pass (e.g., ostream_iterator)
- Forward iterators: Can read/write, multiple passes, only forward direction
- Bidirectional iterators: Can read/write, multiple passes, forward and backward (e.g., list, set)
- Random access iterators: Can read/write, multiple passes, direct access to any element (e.g., vector, deque)
STL Algorithms
The STL provides a rich set of algorithms for common operations on sequences of elements.
Non-modifying Sequence Operations
1#include <iostream>2#include <vector>3#include <algorithm>4using namespace std;56int main() {7 vector<int> vec = {5, 2, 8, 1, 9, 3, 7, 4, 6};89 // count and count_if10 int count_val = count(vec.begin(), vec.end(), 3);11 int count_even = count_if(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; });1213 cout << "Count of 3: " << count_val << endl; // 114 cout << "Count of even numbers: " << count_even << endl; // 41516 // find and find_if17 auto it = find(vec.begin(), vec.end(), 8);18 if (it != vec.end()) {19 cout << "Found 8 at position: " << distance(vec.begin(), it) << endl;20 }2122 auto it2 = find_if(vec.begin(), vec.end(), [](int x) { return x > 7; });23 if (it2 != vec.end()) {24 cout << "First element > 7 is: " << *it2 << endl; // 8 or 9, depending on order25 }2627 // all_of, any_of, none_of (C++11)28 bool all = all_of(vec.begin(), vec.end(), [](int x) { return x > 0; });29 bool any = any_of(vec.begin(), vec.end(), [](int x) { return x > 8; });30 bool none = none_of(vec.begin(), vec.end(), [](int x) { return x < 0; });3132 cout << "All positive: " << boolalpha << all << endl; // true33 cout << "Any > 8: " << any << endl; // true34 cout << "None negative: " << none << endl; // true3536 return 0;37}
Modifying Sequence Operations
1#include <iostream>2#include <vector>3#include <algorithm>4using namespace std;56int main() {7 vector<int> vec = {5, 2, 8, 1, 9, 3, 7, 4, 6};89 // sort10 sort(vec.begin(), vec.end());11 cout << "Sorted vector: ";12 for (int num : vec) {13 cout << num << " "; // 1 2 3 4 5 6 7 8 914 }15 cout << endl;1617 // reverse18 reverse(vec.begin(), vec.end());19 cout << "Reversed vector: ";20 for (int num : vec) {21 cout << num << " "; // 9 8 7 6 5 4 3 2 122 }23 cout << endl;2425 // transform26 vector<int> result(vec.size());27 transform(vec.begin(), vec.end(), result.begin(),28 [](int x) { return x * 2; });2930 cout << "Transformed vector (doubled): ";31 for (int num : result) {32 cout << num << " "; // 18 16 14 12 10 8 6 4 233 }34 cout << endl;3536 // remove and erase (erase-remove idiom)37 vector<int> nums = {1, 2, 3, 4, 5, 2, 6, 2, 7};38 nums.erase(remove(nums.begin(), nums.end(), 2), nums.end());3940 cout << "Vector after removing 2: ";41 for (int num : nums) {42 cout << num << " "; // 1 3 4 5 6 743 }44 cout << endl;4546 return 0;47}
Sorting and Related Operations
1#include <iostream>2#include <vector>3#include <algorithm>4using namespace std;56int main() {7 vector<int> vec = {5, 2, 8, 1, 9, 3, 7, 4, 6};89 // Custom sort (descending order)10 sort(vec.begin(), vec.end(), greater<int>());11 cout << "Sorted in descending order: ";12 for (int num : vec) {13 cout << num << " "; // 9 8 7 6 5 4 3 2 114 }15 cout << endl;1617 // partial_sort18 vector<int> nums = {5, 2, 8, 1, 9, 3, 7, 4, 6};19 partial_sort(nums.begin(), nums.begin() + 4, nums.end());2021 cout << "Partially sorted (first 4): ";22 for (int num : nums) {23 cout << num << " "; // 1 2 3 4 [remaining in any order]24 }25 cout << endl;2627 // nth_element28 vector<int> data = {5, 2, 8, 1, 9, 3, 7, 4, 6};29 nth_element(data.begin(), data.begin() + 4, data.end());3031 cout << "After nth_element (n=4): ";32 for (int num : data) {33 cout << num << " ";34 }35 cout << endl;36 cout << "The 5th element (index 4) is: " << data[4] << endl;37 cout << "Elements before it are <= " << data[4] << endl;38 cout << "Elements after it are >= " << data[4] << endl;3940 return 0;41}
Function Objects (Functors)
Function objects, or functors, are objects that can be called as if they were functions. They are used extensively in STL algorithms.
1#include <iostream>2#include <vector>3#include <algorithm>4#include <functional> // For function objects like less, greater5using namespace std;67// Custom function object8class Multiplier {9private:10 int factor;1112public:13 Multiplier(int f) : factor(f) {}1415 int operator()(int x) const {16 return x * factor;17 }18};1920int main() {21 vector<int> vec = {5, 2, 8, 1, 9};2223 // Using built-in function objects24 sort(vec.begin(), vec.end(), less<int>()); // Ascending2526 cout << "Sorted with less<int>(): ";27 for (int num : vec) {28 cout << num << " "; // 1 2 5 8 929 }30 cout << endl;3132 sort(vec.begin(), vec.end(), greater<int>()); // Descending3334 cout << "Sorted with greater<int>(): ";35 for (int num : vec) {36 cout << num << " "; // 9 8 5 2 137 }38 cout << endl;3940 // Using custom function object41 Multiplier multiplyBy3(3);42 vector<int> result(vec.size());4344 transform(vec.begin(), vec.end(), result.begin(), multiplyBy3);4546 cout << "After multiplying by 3: ";47 for (int num : result) {48 cout << num << " "; // 27 24 15 6 349 }50 cout << endl;5152 // Using lambda as function object (C++11)53 transform(vec.begin(), vec.end(), result.begin(),54 [](int x) { return x + 10; });5556 cout << "After adding 10: ";57 for (int num : result) {58 cout << num << " "; // 19 18 15 12 1159 }60 cout << endl;6162 return 0;63}
Best Practices for Using STL
STL Best Practices
- Prefer STL algorithms over hand-written loops for better readability and performance
- Use the most appropriate container for your needs (e.g., vector for sequential access, map for key-value lookup)
- Understand the complexity guarantees of different operations
- Use const iterators (cbegin(), cend()) when you don't need to modify elements
- Leverage C++11 range-based for loops for cleaner iteration
- Be careful with algorithms that invalidate iterators
Common STL Pitfalls
Common Mistakes
- Using invalidated iterators after container modifications
- Forgetting to use the erase-remove idiom (container.erase(remove(...), container.end()))
- Not checking for end() when using find or other search algorithms
- Assuming sorted order for unordered containers
- Inefficient use of containers (e.g., frequent insertions in the middle of a vector)
- Not leveraging algorithm specializations for different iterator types
Summary
The Standard Template Library is a powerful part of C++ that provides:
- Container classes for storing collections of data
- Iterators for traversing containers
- Algorithms for processing sequences
- Function objects for customizing algorithm behavior
By using the STL, you can write more concise, efficient, and maintainable code, leveraging battle-tested implementations instead of reinventing the wheel. The STL is a key part of modern C++ development and is used in virtually all professional C++ codebases.
Practice Exercise
Create a program that reads a list of integers, stores them in a vector, removes all duplicates, sorts them in descending order, and then calculates their sum and average. Use appropriate STL containers, algorithms, and iterators.
Related Tutorials
Learn about generic programming with C++ templates.
Learn moreMaster object-oriented programming in C++.
Learn moreUnderstand memory management in C++.
Learn more