什么是“跨度”?我什么时候应该使用一个? [英] What is a "span" and when should I use one?
问题描述
最近我得到了在代码中使用 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>
是:
- a的非常轻量级的抽象内存中某个位置的
T
类型的连续值序列。 - 基本上是
结构{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
.
首先,当不使用它时:
- Don'不要在可能需要任何启动和启动对的代码中使用它结束迭代器,例如
std :: sort
,std :: find_if
,std :: 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.
现在何时实际使用它:
使用
span< T>
(分别是span< const T>
),而不是具有长度值的独立的T *
(分别为const T *
)。因此,替换如下函数:
Use
span<T>
(respectively,span<const T>
) instead of a free-standingT*
(respectivelyconst T*
) for which you have the length value. 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){/ *做东西* /}
-
std :: find_if(my_span .begin(),my_span.end(),some_predicate);
...但是绝不会产生任何开销,大多数容器类都会产生。
... 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< T>&
传递给函数时的合理替代方案数据在内存中是连续的。
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!
使用 span $ c更有动力$ c>,您可以在 C ++核心指南中找到-
There's even more motivation for using span
s, which you could find in the C++ core guidelines - but you catch the drift.
它在标准库中-但仅从C ++ 20开始。原因是它与 C ++结合使用时,它的当前形式仍然很新。核心指南项目,该项目从2015年才开始形成。(尽管评论者指出,它的历史更早。)
It is in the standard library - but only as of C++20. The reason is that it's still pretty new in its current form, conceived in conjunction with the C++ core guidelines project, which has only been taking shape since 2015. (Although as commenters point out, it has earlier history.)
它是核心准则的支持库(GSL)。实现:
It's part of the Core Guidelines's Support Library (GSL). Implementations:
- Microsoft / Neil Macintosh的 GSL 包含一个独立的实现:
gsl / span
- GSL-Lite 是整个GSL的单头实现(它并不大,不用担心),包括
span< T>
。
- 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支持[ 14 ]。这些替代的单头实现不依赖于GSL功能:
The GSL implementation does generally assume a platform that implements C++14 support [14]. These alternative single-header implementations do not depend on GSL facilities:
-
martinmoene / span-lite
需要C ++ 98或更高版本 -
tcbrindle / span
需要C ++ 11或更高版本
martinmoene/span-lite
requires C++98 or latertcbrindle/span
requires C++11 or later
请注意,这些不同的span实现在它们所使用的方法/支持功能上有所不同。并且它们也可能与标准库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 going into the standard libraryin 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屋!