【问题标题】:Can std::span iterators outlive the span object they are created from?std::span 迭代器可以比创建它们的 span 对象更长寿吗?
【发布时间】:2021-10-15 06:27:18
【问题描述】:

反过来说,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;
}

https://godbolt.org/z/n1djETane

【问题讨论】:

  • 我无法找到与此相关的规范性文本。从理论上讲,它们应该能够比跨度长(因为跨度本身除了指向底层序列的指针和动态范围的大小之外不包含任何数据成员)

标签: c++ iterator c++20 lifetime std-span


【解决方案1】:

我很欣赏这个问题会连续询问同一问题的正面和负面版本。于是……

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

是的。

span实例销毁后std::span迭代器是否失效?

没有。

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

template<class ElementType, size_t Extent>
  inline constexpr bool ranges::enable_borrowed_range<span<ElementType, Extent>> = true;

在哪里,来自[range.range]/5

给定一个表达式E 使得decltype((E))TT 模型borrowed_­range 仅当从E 表示的对象获得的迭代器的有效性与该对象的生命周期无关.

[注 2:由于迭代器的有效性与类型模型为 borrowed_­range 的对象的生命周期无关,因此函数可以按值接受此类类型的参数并返回获得的迭代器从它那里没有晃来晃去的危险。 — 尾注]

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


gsl::span 的迭代器用于保存指向 span 的指针(这显然会导致迭代器失效),但已更改为 in Feb 2020(我没有查看 cmets 以找到讨论那里,但那个符合标准行为)。

【讨论】:

  • 赞赏。我打算解释相同的问题以使其对搜索引擎友好,但这种倒置是无意的。让我在那边抛出一个“相反”来澄清。
  • @ofo 我只是觉得这很有趣,因为我开始输入“是”。然后回过头来意识到那是错误的,然后输入否。然后意识到两者都是:-)
猜你喜欢
  • 1970-01-01
  • 2012-02-23
  • 2017-01-25
  • 2020-03-16
  • 1970-01-01
  • 1970-01-01
  • 2021-01-19
  • 1970-01-01
  • 2010-12-25
相关资源
最近更新 更多