C++ erase/remove算法指针问题:埃氏筛法实现异常原因排查
故障原因分析
核心本质:lambda捕获规则 + 容器修改导致的取值异常
- 第一段代码的逻辑是安全的:进入循环后立刻将
*ptr的当前值(第一次循环就是2)拷贝到了局部变量p中,lambda通过值捕获拿到的是固定的p的副本,整个remove_if执行过程中判断条件永远是x % 固定值 == 0,所以可以正确移除对应质数的所有倍数。 - 第二段代码的问题出在lambda的捕获逻辑:你在lambda中直接使用了
*ptr,值捕获的时候只会捕获迭代器ptr本身,不会提前把*ptr的取值存下来。
具体执行流程错误推导(以第一次循环为例)
- 进入第一次while循环,
ptr指向integers的首元素,取值为2 - 将2加入质数列表
- 执行
remove_if,遍历vector判断元素是否要移除:- 第一个元素是2,满足
2 % *ptr == 0,remove_if会将后续元素往前移动覆盖当前位置,此时ptr指向的位置的内容被改写为3 - 后续判断其他元素时,
*ptr的取值已经变成了3,判断条件偷偷变成了x % 3 == 0,自然不会再移除2的其他倍数(比如4、6、8等)
- 第一个元素是2,满足
- 本次
erase操作只会移除3的倍数,4就留在了integers中,下一轮循环就会被当作质数加入结果列表
补充说明
对std::vector执行remove_if、erase这类修改容器结构的操作时,所有旧迭代器都会失效,哪怕你提前拷贝了迭代器副本,访问其指向的内容也是未定义行为,可能出现取值错误、程序崩溃等各种异常结果。
内容的提问来源于stack exchange,提问作者hamster1230
相关产品推荐
相关产品推荐

