【std::map与QMap】范围for循环
std::map与QMap在基于范围的for循环遍历中存在显著差异:std::map迭代器返回键值对std::pair,可直接获取键和值;而QMap迭代器仅返回值,需通过it.key()获取键。
·
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
基于范围的for循环遍历std::map与QMap的核心差异,根源在于两者的元素存储模型、迭代器设计逻辑不同(C++标准库与Qt框架的设计哲学差异导致)。以下从原理、表现和原因三方面详细解析:
一、先明确:基于范围的for循环的工作原理
C++11的基于范围的for循环,底层等价于:
{
auto __begin = begin(container); // 容器的起始迭代器
auto __end = end(container); // 容器的结束迭代器
for (; __begin != __end; ++__begin) {
auto var = *__begin; // 核心:迭代器解引用的结果赋值给循环变量
// 循环体逻辑
}
}
因此,循环变量的类型和行为完全由迭代器的解引用操作(operator*())的返回值决定。
二、std::map的遍历行为(键值对直接获取)
1. 元素存储与迭代器设计
std::map<Key, T>是C++标准库的有序关联容器,其核心特征:
- 元素类型:每个元素是
std::pair<const Key, T>(键值对作为一个整体存储),其中键是const的(修改键会破坏红黑树的有序性,因此禁止)。 - 迭代器解引用:
std::map::iterator::operator*()返回std::pair<const Key, T>&(非const迭代器)或const std::pair<const Key, T>&(const迭代器)。
2. 基于范围的for循环表现
循环变量直接对应std::pair,可通过first(键)和second(值)获取键值对:
#include <map>
#include <QString>
#include <QDebug>
int main() {
std::map<QString, QString> smap{
{"std_key1", "std_val1"},
{"std_key2", "std_val2"}
};
// 推荐:使用引用(避免拷贝std::pair,效率更高)
for (const auto& pair : smap) {
qDebug() << "键:" << pair.first << "值:" << pair.second;
}
// 不推荐:值拷贝(会拷贝整个std::pair,效率低)
// for (auto pair : smap) { ... }
return 0;
}
输出:
键:"std_key1" 值:"std_val1"
键:"std_key2" 值:"std_val2"
三、QMap的遍历行为(仅能直接获取值,键需显式迭代器)
1. 元素存储与迭代器设计
QMap<Key, T>是Qt的有序关联容器,其设计与std::map有本质区别:
- 元素模型:逻辑上键和值分离存储,迭代器不直接返回键值对。
- 迭代器解引用:
QMap::iterator::operator*()返回T&(值的引用),operator->()返回T*;键需通过迭代器的key()成员函数获取,值也可通过value()成员函数获取。 - const迭代器:
QMap::const_iterator::operator*()返回const T&(值不可修改),key()仍返回const Key&(键本身不可修改)。
2. 基于范围的for循环的局限
直接遍历QMap时,循环变量仅能拿到值(T或T&),无法获取键;若要同时获取键和值,需使用显式迭代器遍历。
#include <QMap>
#include <QString>
#include <QDebug>
int main() {
QMap<QString, QString> qmap{
{"q_key1", "q_val1"},
{"q_key2", "q_val2"}
};
// 基于范围的for循环:仅能获取值(无法拿到键)
for (const auto& val : qmap) {
qDebug() << "值:" << val; // 仅输出值,无键
}
// 显式迭代器遍历:同时获取键和值(QMap的推荐遍历方式)
for (auto it = qmap.cbegin(); it != qmap.cend(); ++it) {
qDebug() << "键:" << it.key() << "值:" << it.value(); // 或*it(等价于it.value())
}
return 0;
}
输出:
值:"q_val1"
值:"q_val2"
键:"q_key1" 值:"q_val1"
键:"q_key2" 值:"q_val2"
四、额外差异与补充说明
1. 键的可修改性
std::map的键是std::pair的first成员,类型为const Key,绝对不可修改(修改会编译报错)。QMap的键通过it.key()获取,返回const Key&,同样不可修改(Qt设计上禁止修改键,避免破坏有序性)。
2. Qt中获取键值对的替代方案(范围遍历)
若想在Qt中用基于范围的for循环同时遍历键和值,可使用以下技巧(效率略低,仅作补充):
// 方式1:通过keys()获取键列表,再取值(会生成额外的键列表)
for (const auto& key : qmap.keys()) {
qDebug() << "键:" << key << "值:" << qmap.value(key);
}
// 方式2:自定义包装器(Qt 5.10+可结合lambda,略复杂,不推荐)
3. 遍历顺序
两者均为按键的升序遍历(底层均基于红黑树实现),这一点是一致的。
总结
| 特性 | std::map |
QMap |
|---|---|---|
| 范围for循环变量类型 | std::pair<const Key, T>(键值对) |
T(仅值) |
| 获取键的方式 | pair.first |
需显式迭代器的it.key()(范围for循环无法直接获取) |
| 迭代器解引用返回值 | std::pair<const Key, T>& |
T&(值的引用) |
简言之:
std::map遵循C++标准的泛型设计,将键值对作为std::pair整体存储,范围for循环可直接获取键值;QMap更注重Qt的API一致性,迭代器解引用仅返回值,键需通过迭代器方法获取,因此范围for循环只能拿到值。
更多推荐


所有评论(0)