c++中如何使用范围for循环_c++ range-based for遍历容器【实例】

range-based for循环要求容器支持begin()/end()且返回前向迭代器,适用于vector、list、map、array及原生数组;最简形式为for(const auto& item : container);遍历map时item为pair,C++17起推荐用结构化绑定for(const auto& [key, value] : my_map)。

range-based for 循环的基本写法与适用容器

只要容器支持 begin()end() 成员函数(或非成员

重载),且返回的迭代器满足前向迭代器要求,就能用范围 for。标准容器如 std::vectorstd::liststd::mapstd::array 和原生数组都符合。

最简形式是:

for (const auto& item : container) { /* 使用 item */ }
注意这里用 const auto& 是为了不拷贝、不修改——这是最常用也最安全的起点。

  • 想修改元素?用 auto&(非常量左值引用)
  • 需要拷贝一份再处理?用 auto(值语义)
  • 遍历 std::map 时,itemstd::pair 类型,不是单个值

遍历 map 时取 key 和 value 的正确方式

直接写 for (auto& p : my_map) 后,p.first 是 key,p.second 是 value。别试图用结构化绑定以外的方式“拆开”——C++17 起推荐用结构化绑定更清晰:

for (const auto& [key, value] : my_map) {
    std::cout << key << " -> " << value << "\n";
}

注意:[key, value] 是声明,不是访问语法;类型自动推导;如果要修改 value,得把 const auto& 换成 auto&,但 key 仍不可改(因为是 const Key)。

  • auto(无引用)会触发 std::pair 拷贝,对大对象不划算
  • std::unordered_map 同样适用该写法,顺序不保证而已
  • 若编译器不支持 C++17,退回用 p.first/p.second

常见错误:试图在循环中修改容器大小

范围 for 底层依赖 begin()/end() 迭代器。一旦在循环体中调用 push_back()erase() 等改变容器 size 或 layout 的操作,原有迭代器很可能失效,导致未定义行为——不是崩溃就是跳过元素。

  • std::vectorpush_back() 触发 reallocation 时,所有迭代器立即失效
  • std::map 插入一般不使其他迭代器失效,但 erase(it) 会使 it 失效,而范围 for 的内部迭代器正是这个 it
  • 真要边遍历边删?用传统 for + erase() 返回值,或先收集待删 key 再批量处理

自定义类型如何支持 range-based for

只需提供 begin()end() 成员函数(或自由函数),返回可解引用、可递增、可比较相等的迭代器类型即可。例如:

class MyRange {
    int data[3] = {1, 2, 3};
public:
    int* begin() { return data; }
    int* end() { return data + 3; }
};

然后就能写 for (int x : MyRange{}) { ... }。注意:返回裸指针也合法,只要满足迭代器概念;但生产代码建议封装为类迭代器,支持 const 版本和反向遍历。

容易被忽略的是 const 容器的支持——必须额外提供 const_begin()/const_end() 或重载 const 成员函数,否则 const MyRange r; 无法参与范围 for。