为什么 const std::pair<K,V>& in range-based for loop on std::map 不起作用?
Why does const std::pair<K,V>& in range-based for loop on std::map not work?
在 基于范围的 for 循环 中通过 const auto& entry
访问 std::map
的元素时,我得到了对地图中实际数据的引用.另一方面,使用 const std::pair<K,V>&
不会引用 std::map
中的数据
考虑这个例子(用 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;
}
输出:
foo 42 0x11a7eb0
foo 42 0x7ffec118cfc0
我知道 std::map
value_type 是 std::pair<const Key, T>
。但是我真的不明白在第二个基于范围的循环的情况下发生了什么。
std::map<K, V>::value_type
是 std::pair<const K, V>
,而不是 std::pair<K, V>
(参见 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;
}
foo 42 0x2065eb0
foo 42 0x7ffc2d536070
foo 42 0x2065eb0
您的第二个循环有效,因为它正在创建临时 std::pair<std::string, int>
并将其绑定到您的引用 (explanation)。如果您尝试使用非常量引用(因为它不能绑定到临时引用),您会看到它失败了:
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>
'
如您所述,std::map
中的类型是 std::pair<const Key, T>
,而不是 std::pair<Key, T>
。这意味着当我们遍历地图并拉出 const std::pair<Key, T>&
s 时,我们无法获得对该元素的引用,但发生了其他事情。这就是 生命周期延长。 这个循环:
for(const std::pair<std::string, int>& entry : my_map) {
...
}
大致相当于这个循环:
for(const std::pair<std::string, int> entry : my_map) {
...
}
所以你实际上得到了地图中每个条目的副本。
在 基于范围的 for 循环 中通过 const auto& entry
访问 std::map
的元素时,我得到了对地图中实际数据的引用.另一方面,使用 const std::pair<K,V>&
不会引用 std::map
考虑这个例子(用 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;
}
输出:
foo 42 0x11a7eb0
foo 42 0x7ffec118cfc0
我知道 std::map
value_type 是 std::pair<const Key, T>
。但是我真的不明白在第二个基于范围的循环的情况下发生了什么。
std::map<K, V>::value_type
是 std::pair<const K, V>
,而不是 std::pair<K, V>
(参见 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;
}
foo 42 0x2065eb0
foo 42 0x7ffc2d536070
foo 42 0x2065eb0
您的第二个循环有效,因为它正在创建临时 std::pair<std::string, int>
并将其绑定到您的引用 (explanation)。如果您尝试使用非常量引用(因为它不能绑定到临时引用),您会看到它失败了:
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>
'
如您所述,std::map
中的类型是 std::pair<const Key, T>
,而不是 std::pair<Key, T>
。这意味着当我们遍历地图并拉出 const std::pair<Key, T>&
s 时,我们无法获得对该元素的引用,但发生了其他事情。这就是 生命周期延长。 这个循环:
for(const std::pair<std::string, int>& entry : my_map) {
...
}
大致相当于这个循环:
for(const std::pair<std::string, int> entry : my_map) {
...
}
所以你实际上得到了地图中每个条目的副本。