Skip to content

The C++ 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. In this blog, we will explore the fundamentals of the C++ STL and demonstrate its usage with practical examples.

Table of Contents:

  1. STL Containers

    • Vectors
    • Lists
    • Maps
    • Sets
  2. STL Algorithms

    • Sorting
    • Searching
    • Iterating
    • Transforming
  3. STL Functions

    • Lambda Functions
    • Function Objects (Functors)
    • Function Binders
  4. Example Applications

    • Sorting a Vector of Integers
    • Using Map for Data Storage
    • Solving Problems with Algorithms
    • Customizing Functionality with Functors

1. STL Containers

STL provides various container classes to store and manipulate data efficiently. Let's take a closer look at some commonly used containers.

Vectors

Vectors are dynamic arrays that can grow or shrink in size automatically. Here's how you create and use a vector:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> myVector;

    myVector.push_back(1);
    myVector.push_back(2);
    myVector.push_back(3);

    for (int i : myVector) {
        std::cout << i << " ";
    }

    return 0;
}

Lists

Lists are doubly-linked lists, allowing for fast insertions and deletions at both ends. Here's a simple example:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList;

    myList.push_back(1);
    myList.push_back(2);
    myList.push_front(3);

    for (int i : myList) {
        std::cout << i << " ";
    }

    return 0;
}

Maps

Maps are associative containers that store key-value pairs. Here's how you can use a map:

#include <iostream>
#include <map>

int main() {
    std::map<std::string, int> myMap;

    myMap["Alice"] = 25;
    myMap["Bob"] = 30;

    std::cout << "Alice's age: " << myMap["Alice"] << std::endl;

    return 0;
}

Sets

Sets are containers that store unique values. They can be handy when you need to eliminate duplicates from a collection:

#include <iostream>
#include <set>

int main() {
    std::set<int> mySet;

    mySet.insert(1);
    mySet.insert(2);
    mySet.insert(1); // Duplicate value

    for (int i : mySet) {
        std::cout << i << " ";
    }

    return 0;
}

2. STL Algorithms

STL provides a wide range of algorithms that work seamlessly with containers. Here are some examples:

Sorting

Sorting elements in a container is a common task, and STL provides efficient sorting algorithms:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> myVector = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};

    std::sort(myVector.begin(), myVector.end());

    for (int i : myVector) {
        std::cout << i << " ";
    }

    return 0;
}

Searching

STL offers various searching algorithms, such as find, binary_search, and count:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> myVector = {1, 2, 3, 4, 5, 6};

    if (std::binary_search(myVector.begin(), myVector.end(), 3)) {
        std::cout << "Found 3 in the vector." << std::endl;
    } else {
        std::cout << "3 not found." << std::endl;
    }

    return 0;
}

Iterating

STL provides iterators to traverse through containers:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> myVector = {1, 2, 3, 4, 5};

    for (auto it = myVector.begin(); it != myVector.end(); ++it) {
        std::cout << *it << " ";
    }

    return 0;
}

Transforming

You can transform elements in a container using various algorithms like transform:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> myVector = {1, 2, 3, 4, 5};

    std::transform(myVector.begin(), myVector.end(), myVector.begin(),
        [](int x) { return x * 2; });

    for (int i : myVector) {
        std::cout << i << " ";
    }

    return 0;
}

3. STL Functions

STL allows you to work with functions flexibly using concepts like lambda functions, function objects (functors), and function binders.

Lambda Functions

Lambda functions are anonymous functions defined on the fly. They are handy for short, one-off operations:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> myVector = {1, 2, 3, 4, 5};

    // Using a lambda function to multiply each element by 2
    std::for_each(myVector.begin(), myVector.end(),
        [](int &x) { x *= 2; });

    for (int i : myVector) {
        std::cout << i << " ";
    }

    return 0;
}

Functors (Function Objects)

Functors are objects that can be called as if they were functions. They can have their own state, making them more powerful than simple functions:

#include <iostream>
#include <vector>
#include <algorithm>

// Define a functor
struct AddValue {
    int value;
    AddValue(int val) : value(val) {}

    int operator()(int x) const {
        return x + value;
    }
};

int main() {
    std::vector<int> myVector = {1, 2, 3, 4, 5};

    AddValue addFive(5); // Create an instance of the functor

    std::transform(myVector.begin(), myVector.end(), myVector.begin(), addFive);

    for (int i : myVector) {
        std::cout << i << " ";
    }

    return 0;
}

Function Binders

Function bind

ers allow you to fix certain arguments of a function before calling it:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

int main() {
    std::vector<int> myVector = {1, 2, 3, 4, 5};

    // Using a function binder to add 5 to each element
    std::transform(myVector.begin(), myVector.end(), myVector.begin(),
        std::bind(std::plus<int>(), std::placeholders::_1, 5));

    for (int i : myVector) {
        std::cout << i << " ";
    }

    return 0;
}

4. Example Applications

Now that we've covered the basics of STL containers, algorithms, and functions, let's see how you can apply these concepts to real-world scenarios.

Sorting a Vector of Integers

Suppose you have an unsorted vector of integers, and you want to sort it in ascending order:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {5, 1, 4, 2, 3};

    // Sort the vector
    std::sort(numbers.begin(), numbers.end());

    // Print the sorted numbers
    for (int num : numbers) {
        std::cout << num << " ";
    }

    return 0;
}

Using Map for Data Storage

Imagine you need to store and retrieve data with associated keys. You can use a map for this purpose:

#include <iostream>
#include <map>

int main() {
    std::map<std::string, int> scores;

    // Insert key-value pairs
    scores["Alice"] = 95;
    scores["Bob"] = 87;
    scores["Charlie"] = 92;

    // Retrieve and print a specific score
    std::cout << "Charlie's score: " << scores["Charlie"] << std::endl;

    return 0;
}

Solving Problems with Algorithms

STL algorithms are incredibly versatile. Let's say you want to find the sum of all even numbers in a vector:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9};

    // Use std::accumulate with a lambda function
    int sum = std::accumulate(numbers.begin(), numbers.end(), 0, 
        [](int acc, int val) { return val % 2 == 0 ? acc + val : acc; });

    std::cout << "Sum of even numbers: " << sum << std::endl;

    return 0;
}

Customizing Functionality with Functors

Functors can be beneficial when you need to customize functionality in your code. Suppose you want to calculate the sum of squares of a vector of numbers:

#include <iostream>
#include <vector>
#include <algorithm>

struct Square {
    int operator()(int x) const {
        return x * x;
    }
};

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    Square square; // Create an instance of the functor

    // Use std::transform with the functor
    std::transform(numbers.begin(), numbers.end(), numbers.begin(), square);

    for (int num : numbers) {
        std::cout << num << " ";
    }

    return 0;
}