Map in C++ (STL)

In this article, we will discuss what is std::map in C++, and how to use it.

What is std::map in C++?

std::map is a Data Structure provided by Standard Template Library in C++. std::map is an Associative Container that store the data in key-value pairs. It internally uses a self-balancing Binary Search Tree (Red-Black tree) implementation to optimize its operations.

Why do we need std::map in C++?

std::map in C++ serves several important purposes:

  1. It ensures the storage of unique keys only, and maintains them in sorted order based on the assigned sorting criteria.
  2. Due to the sorted order of keys, searching for an element in a map using its key is highly efficient, taking logarithmic time.
  3. Each key in std::map is associated with a single corresponding value, ensuring a one-to-one relationship.
  4. std::map can be utilized as associative arrays, allowing efficient retrieval and manipulation of data using meaningful keys.
  5. Implementation-wise, std::map often utilizes balanced binary trees, ensuring efficient insertion, deletion, and search operations.

By utilizing std::map, C++ programmers can leverage these benefits to organize, access, and manipulate data in a sorted and efficient manner.

Header file for std::map

We need to include the <map> header file to use std::map. Like this,

#include <map>

The std::map is a part of the STL, and header-only library. It is also available in any standard C++ environment, so we don’t need to link any additional libraries to use it.

Creating std::map objects

Syntax to declare std::map objects

To declare a std::map, we need to specify two data type of keys, and values in the map.



    std::map<key_type, value_type> map_name;
    

    Here,

    • key_type: Data type of the keys
    • value_type: Data type of the values

    It created a std::map<key_type, value_type> object map_name. It will store the data as key-value pairs, where keys will be of key_type datatype, and values will be of value_type datatype.

    Let’s see a practical example,

    std::map<std::string, int> wordFrequency;
    

    In the above example, wordFrequency is a map object, where each entry consists of a string key and a integer value. The keys will be sorted in ascending order automatically, and each key will be unique.

    Inserting elements into std::map

    Using insert() member function

    There are two ways to insert elements into a std::map. In first way, we can use the insert() member function of map. It takes a std::pair of a key and a value as argument:

    wordFrequency.insert( std::pair<std::string, int>("this", 22) );
    

    It will add a key-vaue pair into the map.

    Using square brackets []

    We can also use the [] operator to add a key-value pair to the map. It works similarly to array indexing, but instead of index we need tp pass the key in the square brackets i.e. []. Like this,

    wordFrequency["What"] = 22;
    

    It will add a key-vaue pair into the map.

    Different between operator [] and insert() function:

    If the given already exists in the map, then [] operator will update the value of the given key. For example,

    // As key 'what' already exists, 
    // so it will update its value
    wordFrequency["What"] = 99;
    

    Whereas, the insert() function will keep the existing value and ignore the new one, if the given key already exists in the map. The insert() function returns an pair of iterator & bool, where bool value tells if insertion was sucessfull or not. For example,

    auto result = wordFrequency.insert(
                                std::pair<std::string, int>("What", 91) );
    
    if (result.second)
    {
        std::cout<<"Insertion is Successfull \n";
    }
    

    If we try to insert a key-value pair using insert() function, but map already has the given key. Then, in the returned pair, second value will be false.

    Therefore, we should prefer insert() function, if we are not sure that map contains the given key or not.

    Accessing elements in std::map

    To access a value associated with a key in a std::map, we can use the [] operator. For example,

    int value = wordFrequency["this"];
    

    Or we can also use the at() function:

    int val = wordFrequency.at("this");
    

    Important difference between [] opeartor and at() function:

    If the given key does not exist in the map, then
    * The [] operator will insert a default constructed value for the key.
    * Whereas, the at() function will throw an std::out_of_range exception.

    So, the at() function a safer option if you’re not sure whether the key is in the map or not.

    Size of std::map

    std::map provides two useful functions to check its metadata i.e.

    • size() Function : It returns the number of key-value pairs in map.
    • empty Function : It returns a boolean value i.e. true if map has no key-value pairs, otherwise false.
    std::cout << "Size of Map: " << wordFrequency.size() <<std::endl;
    std::cout << "Is Map Empty: " << wordFrequency.empty() <<std::endl;
    

    Output:

    Size of Map: 2
    Is Map Empty: 0
    

    Find elements in std::map

    The find() function can be used for serach for a key-value pair in map using the key. The find() function accepts a key as an argument, and returns an iterator to the element if given key is found, otherwise it returns an iterator pointing to the end of map i.e. map::end(). Let’s see an example,

    auto it = wordFrequency.find("this");
    if ( it != wordFrequency.end())
    {
        // The key exists
        std::cout<< "Key : " << it->first << std::endl;
        std::cout<< "Value : " << it->second << std::endl;
    }
    else
    {
        // The key does not exist
        std::cout << "Key does not exist in map" << std::endl;
    
    }
    

    Output:

    Key : this
    Value : 22
    

    Check if Key exists in std::map using contains()

    Prior to C++20, we needed the find() function to check if a key exists in a map or not. But in C++20, the standard has introduced a new function contains(), to check if map contains the given key or not. It accepts a key as an argument, and returns true if the given key exists in map, otherwise it returns false. For example,

    if ( wordFrequency.contains("this"))
    {
        // The key exists
        std::cout << "Key exists in the map" << std::endl;
    }
    else
    {
        // The key does not exist
        std::cout << "Key does not exist in map" << std::endl;
    
    }
    

    Output:

    Key exists in the map
    

    The contains() function got introduced in C++20 only.

    To prevent runtime errors, before accessing the value of a key, always check if the map contains the given key or not.

    Iterating over a std::map

    Using Iterators

    To Iterate over a std::map, we can use the iterators with the for loop. Like this,

    Iterating over a std::map is straightforward and similar to other containers in C++. Here’s a typical iteration using an iterator:

    for (std::map<std::string, int>::iterator it = wordFrequency.begin();
            it != wordFrequency.end();
            it++)
    {
        std::cout << it->first << " :: " << it->second << '\n';
    }
    

    Output:

    What :: 99
    this :: 22
    

    We iterated over all the elements of map, and for each key-value pair, we printed them on the console.

    Using auto & Range based for-loops

    We can also iterate over a map using a range-based for loop (C++11 and later):

    for (const auto& pair :  wordFrequency)
    {
        std::cout << pair.first << " :: " << pair.second << '\n';
    }
    

    Output:

    What :: 99
    this :: 22
    

    We iterated over all the elements of map, and for each key-value pair, we printed them on the console.

    Removing elements from std::map

    To emove elements from a std::map using the erase() function, like this,

    // Removes the key-value pair from map where key is "this"
    wordFrequency.erase("this"); 
    

    The erase() function accepts a key as an argument and removes the corresponding entry from the map.

    The complete example

    #include <iostream>
    #include <map>
    #include <string>
    #include <iterator>
    
    int main()
    {
        // create a map object, where keys are of string type
        // and values is of integer type
        std::map<std::string, int> wordFrequency;
    
        // Add a key-value pair to map
        wordFrequency.insert(std::pair<std::string, int>("this", 22));
    
        wordFrequency["What"] = 22;
    
        // As key 'what' already exists,
        // so it will update its value
        wordFrequency["What"] = 99;
    
        // Try to insert a key-value pair with duplicate key
        auto result = wordFrequency.insert(
            std::pair<std::string, int>("What", 91));
    
        if (result.second)
        {
            std::cout << "Insertion is Successfull \n";
        }
    
        // Access the value of a key
        int value = wordFrequency["this"];
    
        std::cout << value << std::endl;
    
        // Access the value of a key
        int val = wordFrequency.at("this");
    
        std::cout << value << std::endl;
    
        std::cout << "Size of Map: " << wordFrequency.size() <<std::endl;
        std::cout << "Is Map Empty: " << wordFrequency.empty() <<std::endl;
    
        // search for key in map
        auto it = wordFrequency.find("this");
        if (it != wordFrequency.end())
        {
            // The key exists
            std::cout << "Key : " << it->first << std::endl;
            std::cout << "Value : " << it->second << std::endl;
        }
        else
        {
            // The key does not exist
            std::cout << "Key does not exist in map" << std::endl;
        }
    
        if (wordFrequency.contains("this"))
        {
            // The key exists
            std::cout << "Key exists in the map" << std::endl;
        }
        else
        {
            // The key does not exist
            std::cout << "Key does not exist in map" << std::endl;
        }
    
        for (std::map<std::string, int>::iterator it = wordFrequency.begin();
             it != wordFrequency.end();
             it++)
        {
            std::cout << it->first << " :: " << it->second << '\n';
        }
    
        // Iterate over key-value pairs in map and print them
        for (const auto& pair :  wordFrequency)
        {
            std::cout << pair.first << " :: " << pair.second << '\n';
        }
    
        // Removes the key-value pair from map where key is "this"
        wordFrequency.erase("this"); 
    
    
        // Iterate over key-value pairs in map and print them
        for (const auto& pair :  wordFrequency)
        {
            std::cout << pair.first << " :: " << pair.second << '\n';
        }
    
    
        return 0;
    }

    Output:

    22
    22
    Size of Map: 2
    Is Map Empty: 0
    Key : this
    Value : 22
    Key exists in the map
    What :: 99
    this :: 22
    What :: 99
    this :: 22
    What :: 99

    Summary

    Today, we learned about basic usage details of std::map in C++. For more detailed knowledge, checkout below mentioned related articles for std::map.

    Scroll to Top