ein*_*ica 202 c++ c++-faq cpp-core-guidelines c++20 std-span
最近我有建议span<T>在我的代码中使用's,或者在网站上看到了一些使用span's - 应该是某种容器的答案.但是 - 我在C++标准库中找不到类似的东西.
那么这个神秘的是什么span<T>,以及为什么(或什么时候)使用它是一个好主意,如果它是非标准的?
ein*_*ica 227
A span<T>是:
struct { T * ptr; size_t length; }一堆方便的方法.它以前被称为array_view,甚至更早array_ref.
首先,何时不使用它:
std::sort,std::find_if,std::copy和所有的超级通用模板功能.现在何时实际使用它:
span<T>分别使用(span<const T>而不是)具有长度值的独立T*(分别const T*).所以,替换以下功能:Run Code Online (Sandbox Code Playgroud)void read_into(int* buffer, size_t buffer_size);有:
Run Code Online (Sandbox Code Playgroud)void read_into(span<int> buffer);
哦,跨度很棒!使用span......
意味着您可以使用指针+长度/开始+结束指针组合,就像使用花哨的,拉长的标准库容器一样,例如:
for (auto& x : my_span) { /* do stuff */ }std::find_if(my_span.begin(), my_span.end(), some_predicate);
...但绝对没有大多数容器类产生的开销.
让编译器有时为你做更多的工作.例如,这个:
int buffer[BUFFER_SIZE];
read_into(buffer, BUFFER_SIZE);
Run Code Online (Sandbox Code Playgroud)
成为这个:
int buffer[BUFFER_SIZE];
read_into(buffer);
Run Code Online (Sandbox Code Playgroud)
......这会做你想做的事.另见准则P.5.
const vector<T>&当您希望数据在内存中连续时,是传递给函数的合理替代方法.不再受到高强度C++大师的谴责.
促进静态分析,因此编译器可能能够帮助您捕获愚蠢的错误.
span在#ifndef NDEBUG...中的方法将有一些边界检查代码#endif)使用spans的动机更多,你可以在C++核心指南中找到它- 但是你会发现这种情况.
它在标准库中 - 但仅限于C++ 20.原因在于它与目前的形式相比仍然是新的,与C++核心指南项目一起构思,该项目自2015年以来才刚刚起步.(尽管评论者指出,它有早期的历史.)
它是核心指南支持库(GSL)的一部分.实现:
请注意,您可以将它与早期版本的语言标准一起使用 - C++ 11和C++ 14,而不仅仅是C++ 17.
进一步阅读:您可以在C++ 17,P0122R7之前的最终官方提案中找到所有细节和设计注意事项:span: Neal Macintosh和Stephan J. Lavavej 的对象序列的边界安全视图.虽然有点长.此外,在C++ 20中,跨度比较语义发生了变化(继Tony van Eeerd撰写的这篇简短论文之后).
Gab*_*les 21
Aspan<T>是这样的:
template <typename T>
struct span
{
T * ptr_to_array; // pointer to a contiguous C-style array of data
// (which memory is NOT allocated or deallocated
// by the span)
std::size_t length; // number of elements in the array
// Plus a bunch of constructors and convenience accessor methods here
}
Run Code Online (Sandbox Code Playgroud)
它是围绕 C 样式数组的轻量级包装器,每当 C++ 开发人员使用 C 库并希望使用 C++ 样式数据容器将它们包装起来以实现“类型安全”和“C++ 风格”和“感觉良好”时,C++ 开发人员都会首选它”。:)
@einpoklum在这里很好地介绍了他的回答中的aspan是什么。然而,即使在阅读了他的回答之后,对于一个新来跨越的人来说,仍然很容易有一系列未完全回答的思路问题,例如以下内容:
span与 C 数组有何不同?为什么不只使用其中之一?似乎它只是已知尺寸的其中之一......std::array有什么span不同?std::vector像了std::array?span?所以,这里有一些额外的澄清:
直接引用他的回答——加上我的补充和加粗的括号评论,我用斜体强调:
它是什么?
一个
span<T>是:
- 内存中某处类型的连续值序列的非常轻量级的抽象
T。- 基本上是一个单一的结构
{ T * ptr; std::size_t length; }与一群的方便的方法。(请注意,这明显不同于std::array<>因为 aspan启用了方便的访问器方法,类似于std::array,通过指向 type 的类型T和长度(元素数量)的指针T,而std::array是一个实际的容器,其中包含一个或多个type值T。)- 一个非所属类型(即“引用类型”,而不是“价值型”):它从来不分配,也不解除分配什么和不守智能指针活着。
它以前称为
array_view,甚至更早称为array_ref。
那些粗体部分对一个人的理解至关重要,所以不要错过它们或误读它们!Aspan不是结构的 C 数组,也不是类型T加数组长度的C 数组的结构(这基本上就是std::array 容器的内容),也不是指针结构的 C 数组to typeT加上长度,而是一个包含一个指向 type 的指针的单个结构体,以及length,它是指向 type 的指针所指向的连续内存块中(类型的)元素的数量!这样,您使用的唯一开销TTTspan是存储指针和长度的变量,以及您使用的任何便利访问器函数span。
这是 UNLIKE astd::array<>因为std::array<>实际上为整个连续块分配内存,它是 UNLIKEstd::vector<>因为 astd::vector基本上只是 a每次它填满时std::array也会动态增长(通常大小加倍)并且您尝试向其中添加其他内容. A的std::array大小是固定的,aspan甚至不管理它指向的块的内存,它只是指向内存块,知道内存块有多长,知道C数组中的数据类型在内存中,并提供方便的访问器函数来处理该连续内存中的元素。
std::span自 C++20 起,是 C++ 标准的一部分。您可以在此处阅读其文档:https : //en.cppreference.com/w/cpp/container/span。要了解如何使用谷歌的absl::Span<T>(array, length)在C ++ 11或更高版本的今天,见下文。
std::span<T, Extent>(Extent=“序列中元素的数量,或者std::dynamic_extent如果是动态的”。跨度只是指向内存并使其易于访问,但不管理它!):std::array<T, N>(注意它有一个固定的大小N!):std::vector<T> (根据需要自动动态增加大小):span在 C++11 或更高版本中使用?谷歌已经以其“Abseil”库的形式开源了他们的内部 C++11 库。该库旨在提供 C++14 到 C++20 以及适用于 C++11 及更高版本的功能,以便您可以在今天使用明天的功能。他们说:
与 C++ 标准的兼容性
Google 开发了许多抽象,这些抽象与 C++14、C++17 及更高版本中包含的功能匹配或紧密匹配。使用这些抽象的 Abseil 版本允许您现在访问这些功能,即使您的代码还没有准备好在后 C++11 世界中使用。
span.h标题和absl::Span<T>(array, length)模板类:https : //github.com/abseil/abseil-cpp/blob/master/absl/types/span.h#L153小智 6
Einpoklum 提供的答案很棒,但我必须深入评论部分才能理解一个具体细节,因此这意味着作为澄清该细节的扩展。
首先,什么时候不使用它:
不要在只接受任何一对开始和结束迭代器的代码中使用它,例如 std::sort、std::find_if、std::copy 和所有这些超通用模板化函数。如果您有一个标准库容器(或 Boost 容器等),并且您知道它最适合您的代码,请不要使用它。它无意取代其中任何一个。
任何一对开始和结束迭代器,而不是连续存储的开始和结束指针。
作为一个很少接触迭代器内部的人,在我阅读答案时,我没有意识到迭代器可以迭代链表,而简单的指针(和跨度)则不能。
| 归档时间: |
|
| 查看次数: |
40507 次 |
| 最近记录: |