什么是“跨度"?我什么时候应该使用一个? [英] What is a "span" and when should I use one?

查看:63
本文介绍了什么是“跨度"?我什么时候应该使用一个?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我收到了在我的代码中使用 span<T> 的建议,或者在使用 span 的网站上看到了一些答案 -据说是某种容器.但是 - 我在 C++17 标准库中找不到类似的东西.

Recently I've gotten suggestions to use span<T>'s in my code, or have seen some answers here on the site which use span's - supposedly some kind of container. But - I can't find anything like that in the C++17 standard library.

那么这个神秘的 span<T> 是什么?为什么(或何时)使用它是非标准的好主意?

So what is this mysterious span<T>, and why (or when) is it a good idea to use it if it's non-standard?

推荐答案

是什么?

A span 是:

  • 对内存中某处 T 类型的连续值序列的非常轻量级的抽象.
  • 基本上是一个 struct { T * ptr;std::size_t 长度;} 有很多方便的方法.
  • 非拥有类型(即引用类型" 而不是值类型"):它从不分配或解除分配任何东西,也不使智能指针保持活动状态.
  • A very lightweight abstraction of a contiguous sequence of values of type T somewhere in memory.
  • Basically a struct { T * ptr; std::size_t length; } with a bunch of convenience methods.
  • A non-owning type (i.e. a "reference-type" rather than a "value type"): It never allocates nor deallocates anything and does not keep smart pointers alive.

它以前称为 array_view,甚至更早称为 array_ref.

It was formerly known as an array_view and even earlier as array_ref.

首先,当使用它时:

  • 不要在可能只需要任何一对 start & 的代码中使用它.结束迭代器,例如 std::sortstd::find_ifstd::copy 和所有这些超通用模板化函数.
  • 如果您有一个标准库容器(或 Boost 容器等)并且您知道它适合您的代码,请不要使用它.它无意取代其中任何一个.
  • Don't use it in code that could just take any pair of start & end iterators, like std::sort, std::find_if, std::copy and all of those super-generic templated functions.
  • Don't use it if you have a standard library container (or a Boost container etc.) which you know is the right fit for your code. It's not intended to supplant any of them.

现在是什么时候真正使用它:

Now for when to actually use it:

使用span(分别为span)而不是独立的T*(分别为const T*) 当分配的长度或大小也很重要时.因此,替换如下函数:

Use span<T> (respectively, span<const T>) instead of a free-standing T* (respectively const T*) when the allocated length or size also matter. So, replace functions like:

void read_into(int* buffer, size_t buffer_size);

与:

void read_into(span<int> buffer);

我为什么要使用它?为什么这是一件好事?

哦,跨度太棒了!使用 span...

  • 意味着您可以使用该指针+长度/开始+结束指针组合,就像使用花哨的、拉皮条的标准库容器一样,例如:

  • means that you can work with that pointer+length / start+end pointer combination like you would with a fancy, pimped-out standard library container, e.g.:

  • for (auto& x : my_span) {/* do stuff */}
  • std::find_if(my_span.cbegin(), my_span.cend(), some_predicate);
  • std::ranges::find_if(my_span, some_predicate);(在 C++20 中)

  • for (auto& x : my_span) { /* do stuff */ }
  • std::find_if(my_span.cbegin(), my_span.cend(), some_predicate);
  • std::ranges::find_if(my_span, some_predicate); (in C++20)

...但绝对没有大多数容器类产生的开销.

... but with absolutely none of the overhead most container classes incur.

有时让编译器为你做更多的工作.例如,这个:

lets the compiler do more work for you sometimes. For example, this:

int buffer[BUFFER_SIZE];
read_into(buffer, BUFFER_SIZE);

变成这样:

int buffer[BUFFER_SIZE];
read_into(buffer);

...它会做你想要它做的事情.另见 指南 P.5.

... which will do what you would want it to do. See also Guideline P.5.

是将 const vector& 传递给函数的合理替代方案.再也不怕被C++高手骂了!

is the reasonable alternative to passing const vector<T>& to functions when you expect your data to be contiguous in memory. No more getting scolded by high-and-mighty C++ gurus!

促进静态分析,因此编译器可能能够帮助您发现愚蠢的错误.

facilitates static analysis, so the compiler might be able to help you catch silly bugs.

允许用于运行时边界检查的调试编译检测(即 span 的方法将在 #ifndef NDEBUG 中包含一些边界检查代码... #endif)

allows for debug-compilation instrumentation for runtime bounds-checking (i.e. span's methods will have some bounds-checking code within #ifndef NDEBUG ... #endif)

表示您的代码(使用 span)不拥有指向的内存.

indicates that your code (that's using the span) doesn't own the pointed-to memory.

使用 span 的动机更多,您可以在 C++ 核心指南 - 但你会发现偏差.

There's even more motivation for using spans, which you could find in the C++ core guidelines - but you catch the drift.

是的,std::span 随 C++20 版本的语言一起添加到 C++ 中!

edit: Yes, std::span was added to C++ with the C++20 version of the language!

为什么只在 C++20 中?好吧,虽然这个想法并不新鲜 - 它当前的形式是与 C++ 一起构思的核心指南项目,2015年才开始成型.所以花了一段时间.

Why only in C++20? Well, While the idea is not new - its current form was conceived in conjunction with the C++ core guidelines project, which only started taking shape in 2015. So it took a while.

这是核心指南的一部分的支持库 (GSL).实现:

It's part of the Core Guidelines's Support Library (GSL). Implementations:

  • Microsoft/Neil Macintosh 的 GSL 包含一个独立的实现:gsl/span
  • GSL-Lite 是整个 GSL 的单头实现(它不是那么大,别担心),包括span.
  • Microsoft / Neil Macintosh's GSL contains a standalone implementation: gsl/span
  • GSL-Lite is a single-header implementation of the whole GSL (it's not that big, don't worry), including span<T>.

GSL 实现通常假定一个支持 C++14 的平台 [11].这些替代的单头实现不依赖于 GSL 工具:

The GSL implementation does generally assume a platform that implements C++14 support [11]. These alternative single-header implementations do not depend on GSL facilities:

请注意,这些不同的跨度实现在它们附带的方法/支持功能方面存在一些差异;它们也可能与 C++20 标准库中采用的版本有所不同.

Note that these different span implementations have some differences in what methods/support functions they come with; and they may also differ somewhat from the version adopted into the standard library in C++20.

进一步阅读:您可以在 C++17 之前的最终官方提案 P0122R7 中找到所有细节和设计注意事项:span:对象序列的边界安全视图 作者:Neal Macintosh 和 Stephan J. Lavavej.不过有点长.此外,在 C++20 中,跨度比较语义发生了变化(遵循 这篇短文 作者:Tony van Eerd).

Further reading: You can find all the details and design considerations in the final official proposal before C++17, P0122R7: span: bounds-safe views for sequences of objects by Neal Macintosh and Stephan J. Lavavej. It's a bit long though. Also, in C++20, the span comparison semantics changed (following this short paper by Tony van Eerd).

这篇关于什么是“跨度"?我什么时候应该使用一个?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆