最近我收到了使用建议span<T>
在我的代码中,或者在网站上看到了一些答案,其中使用span
's - 据说是某种容器。但是 - 我在 C++17 标准库中找不到类似的东西。
那么这究竟是什么呢?span<T>
,如果它是非标准的,为什么(或何时)最好使用它?
它是什么?
A span<T>
is:
- 类型的连续值序列的非常轻量级的抽象
T
记忆中的某个地方。
- 基本上是一个
struct { T * ptr; std::size_t length; }
有很多方便的方法。
- 非拥有类型(即“参考类型”而不是“值类型”):它从不分配或释放任何东西,也不保持智能指针处于活动状态。
它以前被称为array_view甚至更早array_ref.
我应该什么时候使用它?
首先,当not使用跨度:
- 不要在代码中使用只能接受任何一对开始和结束迭代器的跨度(例如
std::sort
, std::find_if
, std::copy
和其他模板化函数<algorithm>
),并且也不在采用任意范围的代码中(请参阅C++20 范围信息库关于那些)。跨度比一对迭代器或范围具有更严格的要求:元素连续性以及元素在内存中的存在。
- 如果您有一个标准库容器(或 Boost 容器等),并且您知道它最适合您的代码,请不要使用跨度。 spans 并不是为了取代现有的容器。
现在讨论何时实际使用跨度:
Use span<T>
(分别,span<const T>
)而不是独立的T*
(分别const T*
)当分配的长度或大小也很重要时。因此,替换如下函数:
void read_into(int* buffer, size_t buffer_size);
with:
void read_into(span<int> buffer);
我为什么要使用它?为什么这是一件好事?
哦,跨度太棒了!使用跨度...
-
意味着您可以像使用精美的标准库容器一样使用指针+长度/开始+结束指针组合,例如:
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 中)
...但大多数容器类绝对不会产生任何开销。
-
有时让编译器为您做更多的工作。例如,这个:
int buffer[BUFFER_SIZE];
read_into(buffer, BUFFER_SIZE);
变成这样:
int buffer[BUFFER_SIZE];
read_into(buffer);
...这将做你想做的事。也可以看看指南 P.5.
-
是通过的合理替代方案const vector<T>&
当您希望数据在内存中连续时起作用。再也不用被 C++ 大师骂了!
-
有助于静态分析,因此编译器也许能够帮助您捕获愚蠢的错误。
-
允许调试编译工具进行运行时边界检查(即span
的方法中会有一些边界检查代码#ifndef NDEBUG
... #endif
)
-
表示您的代码(使用跨度)不拥有指向的内存。
使用起来更有动力span
s,您可以在C++ 核心指南- 但你明白了。
但它在标准库中吗?
edit: Yes, std::span已通过该语言的 C++20 版本添加到 C++ 中!
为什么只在 C++20 中?嗯,虽然这个想法并不新鲜,但它目前的形式是与C++ 核心指南项目是2015年才开始成型的,所以花了一段时间。
那么,如果我编写的是 C++17 或更早版本,该如何使用它呢?
它是的一部分核心准则的支持库 (GSL)。实施:
- 微软/尼尔·麦金塔GSL包含一个独立的实现:gsl/span
-
GSL-Lite是整个 GSL 的单头实现(它没有那么大,不用担心),包括
span<T>
.
GSL 实现通常假设一个实现 C++14 支持的平台 [12]。这些替代的单标头实现不依赖于 GSL 设施:
-
martinmoene/span-lite需要 C++98 或更高版本
-
tcbrindle/span需要 C++11 或更高版本
请注意,这些不同的跨度实现在它们附带的方法/支持功能方面存在一些差异;它们也可能与 C++20 标准库中采用的版本有所不同。
进一步阅读:您可以在 C++17 之前的最终官方提案 P0122R7 中找到所有细节和设计注意事项:span:对象序列的边界安全视图作者:Neal Macintosh 和 Stephan J. Lavavej。虽然有点长。此外,在 C++20 中,跨度比较语义发生了变化(以下这篇短文托尼·范·埃尔德)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)