You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C++范围for循环中向vector追加元素为何输出异常?

范围for循环遍历std::vector时push_back导致异常输出的原因分析

问题代码

auto main() -> int {
    std::vector<double> v { 1, 2, 3 };

    for (auto& num : v) {
        std::cout << num << "\n";
        v.push_back(num);
    }

    std::cout << "===========\n";

    for (const auto& num : v) {
        std::cout << num << "\n";
    }
}

实际运行输出

1
1.00938e-320
0
===========
1
2
3
1
1.00938e-320
0

预期输出

1
2
3
===========
1
2
3
1
2
3

疑问

原以为范围for循环是如下代码的语法糖:

for (auto& it{v.begin()}, it != v.end(), it++)

照此逻辑,应该只会出现两种情况:1. 每次迭代都重新计算v.end(),导致无限循环;2. 仅在循环开始前计算一次v.end(),得到预期输出。但实际结果与这两种情况都不符,请问这是为什么?


原因解析

首先纠正你的误解:范围for循环的实际等价逻辑和你想象的不同。根据C++标准,范围for循环会被展开为以下形式:

auto&& __range = v;
auto __begin = __range.begin();
auto __end = __range.end();
for (; __begin != __end; ++__begin) {
    auto& num = *__begin;
    // 循环体代码
}

核心点是:__begin和__end仅在循环启动前初始化一次,后续迭代不会重新计算。问题的根源在于std::vector::push_back的行为:

当push_back新元素时,如果vector当前容量不足以容纳新增元素,会触发内存重新分配——vector会申请一块更大的内存,把旧数据拷贝过去,然后释放旧内存。此时,所有指向旧内存的迭代器(包括范围for循环中保存的__begin和__end)都会彻底失效。

回到你的代码执行流程:

  1. 第一次循环:__begin指向第一个元素1,输出后执行push_back(1)。此时vector的size从3变为4,若初始容量为3(很多实现的默认初始容量等于初始size),则会触发扩容。扩容后,原__begin和__end指向的旧内存已被释放,成为失效迭代器。
  2. 第二次循环:解引用失效的__begin属于未定义行为,输出的1.00938e-320是旧内存中的垃圾值。
  3. 第三次循环:继续移动失效的__begin,解引用得到另一个垃圾值0。
  4. 当失效的__begin与__end比较时,恰好满足__begin != __end不成立,循环终止——这就是为什么循环只执行了3次,却输出异常值。

如果提前给vector预留足够容量(比如在循环前调用v.reserve(6)),push_back不会触发扩容,迭代器也不会失效。此时循环会按你预期的第二种情况执行:遍历初始的3个元素,输出1、2、3,最终vector变为[1,2,3,1,2,3]。

内容的提问来源于stack exchange,提问作者Fei Yu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 16:50:17