Different Approaches to Initialize a Map in C++

Pawara Gunawardena
4 min readNov 12, 2023

--

The map container is available since C++98. It is categorized under associative containers and it stores key-value pairs.

These key-value pairs are ordered based on the keys and the comparison of this ordering uses the comparator of the map instance. Even with multiple insertions of a key, a map keeps a single entry for that key.

Since the first release of the map container, various updates have been made to the map container under various C++ releases over time. The explanation in this article is based on the C++20.

The signature of the map class is similar to the following signature.

template <
typename Key,
typename Tp,
typename Compare = std::less<Key>,
typename Alloc = std::allocator<std::pair<const Key, Tp> > >
class map

There are several additional type definitions within the map class. The following type definitions are associated with the value type of the map instance and the allocator type of the map instance.

typedef std::pair<const Key, Tp>  value_type;
typedef Alloc allocator_type;

The map class has several overloaded constructors. Examples illustrate the use of each constructor in the map class.

1. The default constructor

map()

Example(s):

std::map<std::string, int> mapInstance;
std::map<std::string, int>* pMapInstance = new std::map<std::string, int>();

2. The constructor with comparator and allocator

explicit
map(const Compare& comp, const allocator_type& a = allocator_type())

Example(s):

std::greater<> gtr1;
std::map<std::string, int, std::greater<>> mapInstance1(gtr1);
std::greater<> gtr2;
std::allocator<std::pair<const std::string, int>> alloc1;
std::map<std::string, int, std::greater<>> mapInstance2(gtr2, alloc1);
std::greater<> gtr3;

std::allocator<std::pair<const std::string, int>> alloc2;

std::map<std::string, int, std::greater<>, std::allocator<std::pair<const std::string, int>>>
mapInstance3(gtr3, alloc2);

3. The range constructor

template<typename InputIterator>
map(InputIterator first, InputIterator last)

Example(s):

std::vector<std::pair<int, std::string>> vecInstance{
{10, "ten"}, {30, "thirty"}, {20, "twenty"}
};

std::map<int, std::string>
mapInstanceFromVec(vecInstance.begin(), vecInstance.end());
std::pair<int, std::string> arrInstance[] = {
{20, "apple"}, {10, "orange"}, {30, "pineapple"}
};

std::map<int, std::string> mapInstanceFromArr(arrInstance, arrInstance+3);

4. The range constructor with comparator and allocator

template<typename InputIterator>
map(InputIterator first, InputIterator last,
const Compare& comp, const allocator_type& a = allocator_type())

Example(s):

std::vector<std::pair<int, std::string>> vecInstance{
{10, "ten"}, {30, "thirty"}, {20, "twenty"}
};

std::map<int, std::string, std::greater<>>
mapInstanceFromVec(vecInstance.begin(), vecInstance.end(), std::greater<>());
std::allocator<std::pair<const int, std::string>> alloc;

std::pair<int, std::string> arrInstance[] = {
{20, "apple"}, {10, "orange"}, {30, "pineapple"}
};

std::map<int, std::string, std::greater<>, std::allocator<std::pair<const int, std::string>>>
mapInstanceFromArr(arrInstance, arrInstance+3, std::greater<>(), alloc);

5. Copy Constructor

map(const map&)

Example(s):

std::map<std::string, int> originalMap;
originalMap.insert({"first", 50});
originalMap.insert({"second", 100});
std::map<std::string, int> copyMap(originalMap);

6. Move Constructor

map(map&&)

Example(s):


std::map<std::string, int> originalMap;
originalMap.insert({"first", 500});
originalMap.insert({"second", 1000});
std::map<std::string, int> moveMap(std::move(originalMap));

7. Initializer list constructor

map(initializer_list<value_type> l,
const Compare& comp = Compare(), const allocator_type& a = allocator_type())

Example(s):

std::map<std::string, int> 
initializerListMap1{{"first", 50}, {"second", 100}, {"third", 150}};
std::map<std::string, int, std::greater<>> 
initializerListMap2{{"a", 10}, {"b", 20}, {"c", 30}, {"d", 40}, {"d", 50}};
std::map<int, std::string, std::greater<>>
initializerListMap3({{100, "hundred"}, {1000, "thousand"}, {10, "ten"}}, std::greater<>());
std::map<std::string, int, std::greater<>, std::allocator<std::pair<const std::string, int>>>
initializerListMap4{{"a", 10}, {"b", 20}, {"c", 30}, {"d", 40}, {"d", 50}};
std::allocator<std::pair<const int, std::string>> alloc;

std::map<int, std::string, std::greater<>, std::allocator<std::pair<const int, std::string>>>
initializerListMap5({{100, "hundred"}, {1000, "thousand"}, {10, "ten"}}, std::greater<>(), alloc);

8. Allocator extended default constructor

explicit
map(const allocator_type& a)

Example(s):

std::allocator<std::pair<const std::string, int>> alloc1;
std::map<std::string, int> mapInstance1(alloc1);
std::allocator<std::pair<const std::string, int>> alloc2;

std::map<std::string, int, std::greater<>, std::allocator<std::pair<const std::string, int>>>
mapInstance2(alloc2);

9. Allocator extended copy constructor

map(const map& m, const type_identity_t<allocator_type>& a)

Example(s):

std::allocator<std::pair<const std::string, int>> alloc1;
std::map<std::string, int> originalMap1;
originalMap1.insert({"first", 50});
originalMap1.insert({"second", 100});
std::map<std::string, int> copyMap1(originalMap1, alloc1);
std::allocator<std::pair<const std::string, int>> alloc2;

std::map<std::string, int, std::greater<>, std::allocator<std::pair<const std::string, int>>> originalMap2;
originalMap1.insert({"first", 50});
originalMap1.insert({"second", 100});

std::map<std::string, int, std::greater<>, std::allocator<std::pair<const std::string, int>>>
copyMap2(originalMap2, alloc2);

10. Allocator extended move constructor

map(map&& m, const type_identity_t<allocator_type>& a)

Example(s):

std::allocator<std::pair<const std::string, int>> alloc1;
std::map<std::string, int> originalMap1;
originalMap1.insert({"first", 500});
originalMap1.insert({"second", 1000});
std::map<std::string, int> moveMap1(std::move(originalMap1), alloc1);
std::allocator<std::pair<const std::string, int>> alloc2;

std::map<std::string, int, std::greater<>, std::allocator<std::pair<const std::string, int>>> originalMap2;
originalMap2.insert({"first", 500});
originalMap2.insert({"second", 1000});

std::map<std::string, int, std::greater<>, std::allocator<std::pair<const std::string, int>>>
moveMap2(std::move(originalMap2), alloc2);

11. Allocator extended initializer list constructor

map(initializer_list<value_type> l, const allocator_type& a)

Example(s):

std::allocator<std::pair<const std::string, int>> alloc1;
std::map<std::string, int> initializerListMap1({{"first", 50}, {"second", 100}, {"third", 150}}, alloc1);
std::allocator<std::pair<const std::string, int>> alloc2;
std::map<std::string, int, std::greater<>> initializerListMap2({{"a", 10}, {"b", 20}, {"c", 30}, {"d", 40}, {"d", 50}}, alloc2);
std::allocator<std::pair<const int, std::string>> alloc3;
std::map<int, std::string, std::greater<>, std::allocator<std::pair<const int, std::string>>> initializerListMap3({{100, "hundred"}, {1000, "thousand"}, {10, "ten"}}, alloc3);

12. Allocator extended range constructor

template<typename InputIterator>
map(InputIterator first, InputIterator last, const allocator_type& a)

Example(s):

std::allocator<std::pair<const std::string, int>> alloc1;

std::vector<std::pair<std::string, int>> vecInstance1{
{"ten", 10}, {"thirty", 30}, {"twenty", 20}
};

std::map<std::string, int>
mapInstanceFromVec1(vecInstance1.begin(), vecInstance1.end(), alloc1);
std::allocator<std::pair<const std::string, int>> alloc2;

std::vector<std::pair<std::string, int>> vecInstance2{
{"apple", 20}, {"orange", 10}, {"pineapple", 30}
};

std::map<std::string, int, std::greater<>, std::allocator<std::pair<const std::string, int>>>
mapInstanceFromVec2(vecInstance2.begin(), vecInstance2.end(), alloc2);
std::allocator<std::pair<const std::string, int>> alloc3;

std::pair<std::string, int> arrInstance1[] = {
{"ten", 10}, {"thirty", 30}, {"twenty", 20}
};

std::map<std::string, int>
mapInstanceFromArr1(arrInstance1, arrInstance1+3, alloc3);
std::allocator<std::pair<const std::string, int>> alloc4;

std::pair<std::string, int> arrInstance2[] = {
{"apple", 20}, {"orange", 10}, {"pineapple", 30}
};

std::map<std::string, int, std::greater<>, std::allocator<std::pair<const std::string, int>>>
mapInstanceFromArr2(arrInstance2, arrInstance2+3, alloc4);

The code for each of the examples above can be found here.

--

--

Pawara Gunawardena

Department of Computer Science and Engineering, Faculty of Engineering, University of Moratuwa, Sri Lanka.