最近我收到了在我的代码中使用 span<T>
的建议,或者在网站上看到了一些使用 span
的答案 - 据说是某种容器。但是 - 我在 C++17 标准库中找不到类似的东西。
那么这个神秘的 span<T>
是什么,如果它是非标准的,为什么(或何时)使用它是个好主意?
原文由 einpoklum 发布,翻译遵循 CC BY-SA 4.0 许可协议
最近我收到了在我的代码中使用 span<T>
的建议,或者在网站上看到了一些使用 span
的答案 - 据说是某种容器。但是 - 我在 C++17 标准库中找不到类似的东西。
那么这个神秘的 span<T>
是什么,如果它是非标准的,为什么(或何时)使用它是个好主意?
原文由 einpoklum 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
它是什么?
span<T>
是:T
类型的连续值序列的非常轻量级的抽象。struct { T * ptr; std::size_t length; }
有一堆方便的方法。它以前称为
array_view
甚至更早为array_ref
。我应该什么时候使用它?
首先,什么时候 不 使用跨度:
std::sort
,std::find_if
,std::copy
和其他模板函数<algorithm>
),并且不在采用任意范围的代码中(有关这些 信息,请参阅 C++20 范围库)。跨度比一对迭代器或范围有更严格的要求:元素连续性和元素在内存中的存在。现在了解何时实际使用跨度:
int buffer[BUFFER_SIZE]; read_into(buffer);
”`
…这将做你想做的事。另见 指南 P.5 。
当您希望数据在内存中连续时,将
const vector<T>&
传递给函数是合理的替代方法。再也不用被高大上的 C++ 大师骂了!有助于静态分析,因此编译器可能能够帮助您捕获愚蠢的错误。
允许用于运行时边界检查的调试编译工具(即
span
的方法将在#ifndef NDEBUG
…#endif
中有一些边界检查代码)表示您的代码(使用跨度)不拥有指向的内存。
使用
span
s 的动机甚至更多,您可以在 C++ 核心指南 中找到它 - 但您会发现偏差。但它在标准库中吗?
编辑: 是的,
std::span
是使用 C++20 版本的语言添加到 C++ 中的!为什么只在 C++20 中?好吧,虽然这个想法并不新鲜——它目前的形式是与 C++ 核心指南 项目一起构思的,该项目在 2015 年才开始形成。所以花了一段时间。
那么如果我正在编写 C++17 或更早版本,我该如何使用它呢?
它是 核心指南 的支持库 (GSL) 的一部分。实现:
gsl/span
span<T>
。GSL 实现通常假设一个实现 C++14 支持的平台 [ 12 ]。这些替代的单头实现不依赖于 GSL 设施:
martinmoene/span-lite
需要 C++98 或更高版本tcbrindle/span
需要 C++11 或更高版本请注意,这些不同的 span 实现在它们附带的方法/支持功能方面存在一些差异;它们也可能与 C++20 标准库中采用的版本有所不同。
进一步阅读: 您可以在 C++17、P0122R7 之前的最终官方提案中找到所有细节和设计注意事项: 跨度:Neal Macintosh 和 Stephan J. Lavavej 的对象序列的边界安全视图。虽然有点长。此外,在 C++20 中,跨度比较语义发生了变化(在 Tony van Eerd 的 这篇简短论文 之后)。