C++ 23 – <flat_map> Header
Last Updated :
22 Sep, 2023
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++
#include <flat_map>
#include <iostream>
using namespace std;
int main()
{
flat_map< int , string> myFlatMap
= { { 1, "Geeks" }, { 3, "for" }, { 2, "Geeks" } };
for ( const auto & pair : myFlatMap) {
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++
#include <flat_map>
#include <iostream>
using namespace std;
int main()
{
flat_map< int , string> myMap = { { 1, "Geeks" },
{ 2, "for" },
{ 3, "Geeks" },
{ 4, "Coding" } };
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++
#include <flat_map>
#include <iostream>
using namespace std;
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" ));
myMap.insert(make_pair(4, "Coding" ));
cout << "Map before erasing:" << endl;
for ( const auto & pair : myMap) {
cout << "Key: " << pair.first
<< ", Value: " << pair.second << endl;
}
myMap.erase(3);
cout << "Map after erasing by key:" << endl;
for ( const auto & pair : myMap) {
cout << "Key: " << pair.first
<< ", Value: " << pair.second << endl;
}
myMap.clear();
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++
#include <flat_map>
#include <iostream>
using namespace std;
int main()
{
flat_map< int , string> myMap
= { { 1, "Geeks" }, { 2, "for" }, { 3, "Geeks" } };
cout << "Size of the map: " << myMap.size() << endl;
cout << "Maximum possible size of the map: "
<< myMap.max_size() << endl;
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++
#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" ));
if (myMap.contains(2)) {
cout << "Key 2 exists in the map." << endl;
}
auto it = myMap.find(3);
if (it != myMap.end()) {
cout << "Value at key 3: " << it->second << endl;
}
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.
Share your thoughts in the comments
Please Login to comment...