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

为何std::move与std::list结合自定义视图会引发无限递归?

问题分析与解答

问题现象

自定义ContainerView视图适配std::list时,若将std::move(my_list)传入std::views::all构造视图,迭代时会无限重复打印元素;但换成std::vector则正常,直接迭代std::move后的std::list也无异常。

核心原因

问题出在自定义视图的实现违反了C++20范围视图的语义约束:视图不应存储构造时的迭代器,而应在需要时从内部持有的范围动态获取迭代器。

你的ContainerView在构造时先获取输入视图的迭代器并存储为begin_和end_,再将输入视图移动到内部成员range_。这种做法存在致命问题:

  • 当输入视图被移动后,存储的迭代器可能不再指向range_当前持有的范围。对于std::vector,这属于未定义行为,只是碰巧在你的实现中能正常工作;
  • 对于std::list,虽然移动容器后迭代器本身仍指向原元素,但由于range_是移动后的新容器,存储的end_迭代器与range_实际的尾后迭代器在比较时可能永远不相等(部分实现中std::list的迭代器比较会关联容器的内部状态),导致循环无法终止,陷入无限打印。

修正方案

修改ContainerView,仅存储内部的Range对象,在begin()和end()成员函数中动态获取当前范围的迭代器:

#include <concepts>
#include <iostream>
#include <list>
#include <ranges>
#include <vector>

template <std::ranges::input_range Range>
  requires std::ranges::view<Range>
class ContainerView : public std::ranges::view_interface<ContainerView<Range>> {
private:
  Range range_ {};

public:
  constexpr ContainerView() = default;

  constexpr ContainerView(Range r)
      : range_(std::move(r))
  {
  }

  constexpr auto begin() const { return std::begin(range_); }
  constexpr auto end() const { return std::end(range_); }
};

int main()
{
  std::list my_list { 1, 2, 3 };
  auto my_container_view { ContainerView(std::views::all(std::move(my_list))) };

  for (auto const& c : my_container_view)
    std::cout << c << '\n';
}

这样修改后,每次迭代都会从当前的range_获取正确的迭代器,无论内部范围是否被移动,都能保证迭代行为符合预期。


内容的提问来源于stack exchange,提问作者Abel Sen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 21:45:55