Share:

STL

advanced

Part of Advanced C++

Theory

The Standard Template Library (STL) is a powerful set of C++ template classes and functions that provide common data structures and algorithms. It has three main components: containers, iterators, and algorithms.

Containers Overview

STL containers are data structures that store collections of objects:

| Container | Description | Header | |-----------|-------------|--------| | vector | Dynamic array (contiguous memory) | <vector> | | deque | Double-ended queue | <deque> | | list | Doubly-linked list | <list> | | map | Key-value pairs (sorted by key) | <map> | | set | Unique sorted elements | <set> | | unordered_map | Key-value pairs (hash table) | <unordered_map> | | unordered_set | Unique elements (hash table) | <unordered_set> | | stack | LIFO adapter | <stack> | | queue | FIFO adapter | <queue> | | string | Character array with operations | <string> |

Vector

std::vector is a dynamic array that grows automatically:

#include <vector>
 
vector<int> vec;               // Empty vector
vector<int> vec2(10, 5);       // 10 elements, all 5
vector<int> vec3 = {1, 2, 3};  // Initializer list
 
vec.push_back(42);             // Add to end
vec.pop_back();                // Remove from end
int size = vec.size();         // Number of elements
bool empty = vec.empty();      // Check if empty
vec.clear();                   // Remove all elements
 
// Access
int first = vec[0];            // Unchecked access
int firstSafe = vec.at(0);     // Bounds-checked (throws out_of_range)
int* data = vec.data();        // Raw pointer to underlying array
 
// Insert/erase
vec.insert(vec.begin() + 1, 99);
vec.erase(vec.begin() + 2);

Capacity management:

cout << vec.size();      // Number of elements
cout << vec.capacity();  // Allocated space
vec.reserve(100);        // Pre-allocate memory
vec.shrink_to_fit();     // Reduce capacity to fit size

Map

std::map stores key-value pairs sorted by key:

#include <map>
 
map<string, int> ages;
ages["Alice"] = 30;
ages["Bob"] = 25;
 
// Insertion
ages.insert({"Charlie", 35});
ages.emplace("Dave", 28);  // More efficient
 
// Lookup
int age = ages["Alice"];          // Creates entry if missing!
auto it = ages.find("Bob");       // Returns iterator or end()
int count = ages.count("Alice");  // 1 if exists, 0 if not
 
// Iteration
for (const auto& [name, age] : ages) {
    cout << name << ": " << age << endl;
}

Use unordered_map for O(1) average lookup (no ordering):

#include <unordered_map>
unordered_map<string, int> scores;  // Faster, but not sorted

String

std::string provides rich functionality:

#include <string>
 
string s = "Hello";
s += " World";               // "Hello World"
int len = s.length();        // 11
int size = s.size();         // Also 11
 
// Substring
string sub = s.substr(0, 5);  // "Hello"
size_t pos = s.find("World"); // 6
size_t notFound = s.find("xyz"); // string::npos
 
// Modification
s.insert(5, " C++");        // "Hello C++ World"
s.replace(6, 3, "Beautiful"); // "Hello Beautiful World"
s.erase(5, 8);              // "Hello World"
 
// Conversion
const char* cstr = s.c_str();
int num = stoi("42");
string str = to_string(3.14);

Iterators

Iterators are objects that point to elements in a container, like pointers:

vector<int> vec = {10, 20, 30, 40, 50};
 
// begin()/end() — forward iteration
for (auto it = vec.begin(); it != vec.end(); ++it) {
    cout << *it << " ";  // Dereference to get value
}
 
// rbegin()/rend() — reverse iteration
for (auto it = vec.rbegin(); it != vec.rend(); ++it) {
    cout << *it << " ";  // 50 40 30 20 10
}
 
// cbegin()/cend() — const iterators (read-only)
for (auto it = vec.cbegin(); it != vec.cend(); ++it) {
    // *it = 99;  // Error! Read-only
}

Iterator categories:

  • Input iterators: Read once, forward only (istream_iterator)
  • Output iterators: Write once, forward only (ostream_iterator)
  • Forward iterators: Read/write, forward only (forward_list)
  • Bidirectional iterators: Forward and backward (list, set, map)
  • Random access iterators: Direct element access (vector, deque, string)

Algorithms

STL provides many algorithms in <algorithm>:

#include <algorithm>
#include <numeric>
 
vector<int> v = {5, 2, 8, 1, 9, 3, 7, 4, 6};
 
// Sorting
sort(v.begin(), v.end());                    // Ascending
sort(v.begin(), v.end(), greater<int>());    // Descending
 
// Searching
auto it = find(v.begin(), v.end(), 5);       // Find 5
bool exists = binary_search(v.begin(), v.end(), 5);  // Sorted range
 
// Modifying
reverse(v.begin(), v.end());                 // Reverse in place
copy(v.begin(), v.end(), vec2.begin());      // Copy to another
fill(v.begin(), v.end(), 0);                 // Fill with 0
 
// Min/Max
int minVal = *min_element(v.begin(), v.end());
int maxVal = *max_element(v.begin(), v.end());
 
// Accumulate (in <numeric>)
int sum = accumulate(v.begin(), v.end(), 0);
int product = accumulate(v.begin(), v.end(), 1, multiplies<int>());
 
// Count
int c = count(v.begin(), v.end(), 3);
 
// Transform
transform(v.begin(), v.end(), v.begin(),
          [](int x) { return x * 2; });

Auto and Range-Based For Loops

Modern C++ (C++11+) makes working with containers much easier:

vector<int> vec = {10, 20, 30};
 
// Range-based for — by value (copies)
for (int x : vec) {
    x = 0;  // Doesn't modify original
}
 
// Range-based for — by reference (modifies)
for (int& x : vec) {
    x *= 2;
}
 
// Range-based for — const reference (read-only, efficient)
for (const int& x : vec) {
    cout << x << " ";
}
 
// With auto (recommended)
for (const auto& x : vec) { cout << x << " "; }
 
// Iterating over a map
map<string, int> m = {{"a", 1}, {"b", 2}};
for (const auto& [key, value] : m) {
    cout << key << ": " << value << endl;
}

Prefer range-based for loops over index-based loops when you need to iterate over all elements. It's cleaner, less error-prone, and works with all containers.

Practical Examples

Example 1: Word Frequency Counter
cpp
Example 2: Student Grade Management
cpp

When you know the final size of a vector, use reserve() to pre-allocate memory. This avoids repeated reallocations as the vector grows, significantly improving performance.

Exercises

Vector Operations

easy

Create a vector of integers. Fill it with the numbers 1-20. Then: remove all even numbers, double each remaining number, and print the result in reverse order.

Expected Output:

38 34 30 26 22 18 14 10 6 2

Map-Based Phone Directory

medium

Create a phone directory using std::map. Implement a program that lets the user add, lookup, and list contacts. Store the data in alphabetical order using the map's natural ordering.

Expected Output:

All contacts:\nAlice: 555-1234\nBob: 555-5678\nCharlie: 555-9012\n\nFinding Alice: 555-1234\nFinding Dave: Not found

String Processing with Algorithms

medium

Write a program that reads a sentence, splits it into words, filters out words shorter than 3 characters, converts remaining words to uppercase, sorts them alphabetically, and removes duplicates.

Expected Output:

Processed words: BAT CAT HAT MAT SAT THE WITH

Mini Quiz

Mini Quiz

Mini Project

Mini Project: Movie Database with STL

Build a movie database application using STL containers and algorithms. Store movie information, support searching, sorting, and filtering operations.

Requirements:

    Bonus Challenge

    Add a feature to recommend movies based on a given movie's genres. Implement a simple TF-IDF search over movie descriptions.