为什么 const std::p air<K,V>& 在 std::map 上基于范围的 for 循环不起作用?

Why does const std::pair<K,V>& in range-based for loop on std::map not work?

本文关键字:std 范围 于范围 for 不起作用 循环 lt air const map 为什么      更新时间:2023-10-16

在基于循环的范围内通过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;
}

示例输出:

foo 42 0x2065eb0
foo 42 0x7ffc2d536070
foo 42 0x2065eb0

您的第二个循环之所以有效,是因为它创建了一个临时std::pair<std::string, int>并将其绑定到您的引用(解释(。如果您尝试使用非常量引用(因为它不能绑定到临时引用(,您可能会看到它失败:

错误:从类型为'std::pair<const std::__cxx11::basic_string<char>, int>'的表达式初始化类型为'std::pair<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) {
...
}

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