std::span 迭代器可以比创建它们的 span 对象寿命更长吗?

ofo*_*ofo 4 c++ iterator lifetime c++20 std-span

换句话说,反过来,std::span迭代器在span实例被销毁后会失效吗?

我有一个向量需要用不同的布局进行迭代。我试图std::span避免编写大量迭代器样板或引入外部库依赖项。简化示例:

#include <iostream>
#include <span>
#include <vector>

template <size_t N>
struct my_view {
  std::vector<int> vec;

  auto as_span() {
    return std::span<int[N]>((int(*)[N])vec.data(), vec.size() / N);
  }

  auto begin() {
    return as_span().begin();
  }

  auto end() {
    return as_span().end();
  }
};

int main() {
  std::vector vec {1, 2, 3, 4, 5, 6};
  my_view<2> pairs {std::move(vec)};
  for (auto pair : pairs) {
    std::cout << pair[0] << " " << pair[1] << std::endl;
  }
  my_view<3> triplets {std::move(pairs.vec)};
  for (auto triplet : triplets) {
    std::cout << triplet[0] << " " << triplet[1] << " " << triplet[2] << std::endl;
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/n1djETane

Bar*_*rry 5

我很欣赏这个问题连续询问同一问题的正面和负面版本。因此...

\n
\n

迭代器能否std::span比创建它们的 Span 对象寿命更长?

\n
\n

是的。

\n
\n

std::spanSpan实例销毁后迭代器会失效吗?

\n
\n

不。

\n

这就是为什么你在[span.syn]中看到:

\n
template<class ElementType, size_t Extent>\n  inline constexpr bool ranges::enable_borrowed_range<span<ElementType, Extent>> = true;\n
Run Code Online (Sandbox Code Playgroud)\n

其中,来自[range.range]/5

\n
\n

给定一个表达式,例如 ,Edecltype((E))当从 表示的对象获取的迭代器的有效性与该对象的生命周期无关时才进行建模。TTborrowed_\xc2\xadrangeE

\n
\n
\n

[注2:由于迭代器的有效性与类型模型的对象的生命周期无关borrowed_\xc2\xadrange,因此函数可以按值接受此类类型的参数并返回从中获得的迭代器,而不会出现悬空的危险。\xe2\x80\x94尾注]

\n
\n

如果 aspan的迭代器与 的生命周期相关联span,那么这样做是无效的——span必须是非借用的(例如,vector<T>显然不是借用的)。

\n
\n

gsl::span\ 的迭代器用于保留指向span(这显然会导致迭代器无效) 的指针,但这一点在 2020 年 2 月发生了变化(我没有查看评论以找到那里的讨论,但那个符合标准行为)。

\n