C++23 introduces a new header, <flat_map>, which revolutionizes the manner we store and retrieve key-value pairs. Traditionally, C++ developers have depended on map and unordered_map containers for associative storage. However, the flat_map container gives a singular technique by combining the advantages of each ordered and contiguous storage. In this article, we will explore the <flat_map> header, syntax, and its advantages through examples and use cases.
std::flat_map
The std::flat_map is a class template of flat_map container that provides an efficient data structure for storing key-value pairs.
- flat_map has the combined functionality of a map and vector.
- flat_map ensures that values are stored in sorted order primarily based on the keys, and also maintains the elements in a contiguous memory layout. This combination allows for fast access, random access, and faster traversal than its counterparts.
- To use flat_map, we include the <flat_map> header in C++23 and declare an instance of the container with the desired key and value types.
Syntax of std::flat_map
flat_map < keyType, valueType > name;
std::flat_map Initialization
We can initialize a flat_map container in C++ using the following methods:
1. Using the Initializer List
We can initialize std::flat_map by proving key and value pairs in the initializer list.
Example
flat_set <int, string> object_name { {3, "three"}, {1, "one"}, {4, "four"} };
2. Using the Range Constructor
We can use the range constructor to initialize the std::flat_map object with key and value pairs by specifying the range using the starting iterator and ending iterator.
Example
flat_map <keyType, valueType > object_name(startingIterator, endingIterator);
3. Using the Assignment Operator
We can simply initialize the flat_map object object with another already existing flat_map object using an assignment operator.
Example
flat_set <keyType, valueType > object_name; object_name = prev_object;
4. Using the Move Assignment Operator
We can initialize a std::flat_map using the move assignment operator. This way of initializing a std::flat_map is memory efficient because the assigned object simply points to the existing memory location where the data is stored without creating unnecessary copies of data.
Example
flat_set <keyType, valueType > object_name; object_name = move(prev_object);
Example of std::flat_map
// C++ program to illustrate the flat_map header #include <flat_map> #include <iostream> using namespace std;
int main()
{ // Create an instance of flat_map with int keys and
// string values using an initializer list
flat_map< int , string> myFlatMap
= { { 1, "Geeks" }, { 3, "for" }, { 2, "Geeks" } };
for ( const auto & pair : myFlatMap) {
// Iterate over each key-value pair in the flat_map
// and print the key and value
cout << "Key: " << pair.first
<< ", Value: " << pair.second << endl;
}
return 0;
} |
Output
Key: 1, Value: Geeks Key: 2, Value: Geeks Key: 3, Value: for
Commonly Used Methods
The following are some member functions for basic operation on the flat_map container:
1. Iterators
Iterators are used to traverse the container. The following function returns iterators to the flat_map containers:
- begin() – Returns an iterator pointing to the first element in the flat_map.
- end() – Returns an iterator pointing to the position just after the last element in the flat_map.
Example
// C++ program to traverse the flat_map using begin() and // end() #include <flat_map> #include <iostream> using namespace std;
int main()
{ flat_map< int , string> myMap = { { 1, "Geeks" },
{ 2, "for" },
{ 3, "Geeks" },
{ 4, "Coding" } };
// Iterate over the map using begin() and end()
cout << "All key-value pairs in the map:" << endl;
for ( auto it = myMap.begin(); it != myMap.end(); ++it) {
cout << "Key: " << it->first
<< ", Value: " << it->second << endl;
}
return 0;
} |
Output
All key-value pairs in the map: Key: 1, Value: Geeks Key: 2, Value: for Key: 3, Value: Geeks Key: 4, Value: Coding
2. Modifiers
- pair insert(keyvalue, mapvalue): Adds a new element to the map.
- erase(iterator position): Removes the element at the position pointed by the iterator.
- erase(const key_type& g): Removes the key value ‘g’ from the map.
- clear() – Removes all the elements from the map.
Example
// C++ program to demonstrate the usage of // pair insert(), erase(key), erase(position) // clear() functions #include <flat_map> #include <iostream> using namespace std;
int main()
{ flat_map< int , string> myMap;
// Insert key-value pairs using insert()
myMap.insert(make_pair(1, "Geeks" ));
myMap.insert(make_pair(2, "for" ));
myMap.insert(make_pair(3, "Geeks" ));
myMap.insert(make_pair(4, "Coding" ));
// Print the map before erasing
cout << "Map before erasing:" << endl;
for ( const auto & pair : myMap) {
cout << "Key: " << pair.first
<< ", Value: " << pair.second << endl;
}
// Erase an element by key using erase()
myMap.erase(3);
// Print the map after erasing by key
cout << "Map after erasing by key:" << endl;
for ( const auto & pair : myMap) {
cout << "Key: " << pair.first
<< ", Value: " << pair.second << endl;
}
// Clear the map using clear()
myMap.clear();
// Check if the map is empty after clearing
if (myMap.empty()) {
cout << "The map is empty after clearing." << endl;
}
return 0;
} |
Output
Map before erasing: Key: 1, Value: Geeks Key: 2, Value: for Key: 3, Value: Geeks Key: 4, Value: Coding Map after erasing by key: Key: 1, Value: Geeks Key: 2, Value: for Key: 4, Value: Coding The map is empty after clearing.
3. Size
- size() – Returns the number of elements in the flat_map.
- max_size() – Returns the maximum number of elements that the flat_map can hold.
- empty() – Returns whether the flat_map is empty.
Example
// C++ program to demonstrate the usage of // size(), max_size() and empty() functions #include <flat_map> #include <iostream> using namespace std;
int main()
{ flat_map< int , string> myMap
= { { 1, "Geeks" }, { 2, "for" }, { 3, "Geeks" } };
// Get the size of the map using size()
cout << "Size of the map: " << myMap.size() << endl;
// Get the maximum possible size of the map using
// max_size()
cout << "Maximum possible size of the map: "
<< myMap.max_size() << endl;
// Check if the map is empty using empty()
if (myMap.empty()) {
cout << "The map is empty." << endl;
}
else {
cout << "The map is not empty." << endl;
}
return 0;
} |
Output
Size of the map: 3 Maximum possible size of the map: 256204778801521550 The map is not empty.
4. Map operations
- bool contains(const key_type& g) const – Returns true if there is an element present with key value ‘g’ in the flat_map, else it returns false.
- find(const key_type & g) – Returns an iterator pointing to an element with the key value ‘g’, or end() if such an element is not present in the flat_map.
- count(const key_type & g) const – Returns the number of elements with key value ‘g’.
Example
// C++ program to demonstrate the usage of // contains(), find() and count() functions #include <flat_map> #include <iostream> int main()
{ flat_map< int , string> myMap;
myMap.insert(make_pair(1, "Geeks" ));
myMap.insert(make_pair(2, "for" ));
myMap.insert(make_pair(3, "Geeks" ));
// Check if a key exists using contains()
if (myMap.contains(2)) {
cout << "Key 2 exists in the map." << endl;
}
// Find an element by key using find()
auto it = myMap.find(3);
if (it != myMap.end()) {
cout << "Value at key 3: " << it->second << endl;
}
// Count the number of elements with a specific key
// using count()
int key = 2;
int numOccurrences = myMap.count(key);
cout << "Number of occurrences of key " << key << ": "
<< numOccurrences << endl;
return 0;
} |
Output
Key 2 exists in the map. Value at key 3: Geeks Number of occurrences of key 2: 1
Advantages of flat_map
- One of the key benefits of flat_map is its ability to provide fast search, insertion, and deletion operations while maintaining the sorted order.
- It offers logarithmic time complexity for these operations, making it appropriate for programs that require efficient key-value storage and retrieval.
- The contiguous memory format of flat_map allows for cache-friendly access patterns, in addition to improving performance.
Applications of flat_map
flat_map finds its utility in a wide range of situations. For example, consider a dictionary application where words are stored as keys, and their definitions are stored as values. By the usage of <flat_map>, we will quickly look for a phrase’s definition based on its key.
Another use case is in leaderboard management, where the scores act as keys and participant names act as values. With flat_map, we can efficiently retrieve the top scores or perform operations like updating scores or removing off players.
Conclusion
C++23’s flat_map header offers a powerful and efficient solution for key-value storage and retrieval. By combining the benefits of ordered and contiguous storage, flat_map gives fast and sorted access to elements.