When accessing the elements of a std::map
via const auto& entry
in a range-based for loop I get a reference to the actual data in the map. Using const std::pair<K,V>&
on the other hand does not give a reference to the data in the std::map
Consider this example (compiled with gcc 7.4, -std=c++14)
#include <map>
#include <string>
#include <iostream>
int main(void)
{
std::map<std::string, int> my_map {{"foo", 42}};
for(const auto& entry : my_map)
std::cout << entry.first << ' ' << entry.second << ' ' << &(entry.second) << std::endl;
for(const std::pair<std::string, int>& entry : my_map)
std::cout << entry.first << ' ' << entry.second << ' ' << &(entry.second) << std::endl;
return 0;
}
Output:
foo 42 0x11a7eb0
foo 42 0x7ffec118cfc0
I am aware that the std::map
value_type is std::pair<const Key, T>
. But I don't really understand what is happening in the case of the second range-based loop.
std::map<K, V>::value_type
is std::pair<const K, V>
, not std::pair<K, V>
(see cppreference)
#include <map>
#include <string>
#include <iostream>
int main(void)
{
std::map<std::string, int> my_map {{"foo", 42}};
for(const auto& entry : my_map)
std::cout << entry.first << ' ' << entry.second << ' ' << &(entry.second) << std::endl;
for(const std::pair<std::string, int>& entry : my_map)
std::cout << entry.first << ' ' << entry.second << ' ' << &(entry.second) << std::endl;
for(const std::pair<const std::string, int>& entry : my_map)
std::cout << entry.first << ' ' << entry.second << ' ' << &(entry.second) << std::endl;
return 0;
}
Example output:
foo 42 0x2065eb0
foo 42 0x7ffc2d536070
foo 42 0x2065eb0
Your second loop works because it's creating a temporary std::pair<std::string, int>
and binding it to your reference (explanation). You can see it fail if you try to use a non-const reference instead (since it can't bind to a temporary):
error: invalid initialization of reference of type '
std::pair<std::__cxx11::basic_string<char>, int>&
' from expression of type 'std::pair<const std::__cxx11::basic_string<char>, int>
'
As you mentioned, the types inside the std::map
are std::pair<const Key, T>
, not std::pair<Key, T>
. This means that when we iterate over the map and pull out const std::pair<Key, T>&
s, we can't get a reference to the element, but something else is happening. This something else is lifetime extension. This loop:
for(const std::pair<std::string, int>& entry : my_map) {
...
}
Is roughly equivalent to this loop:
for(const std::pair<std::string, int> entry : my_map) {
...
}
So you're actually getting a copy of every entry in the map.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With