为什么 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_typestd::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;
}

Example output:

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) {
    ...
}

所以你实际上得到了地图中每个条目的副本。