Недавно я получил предложения использовать span<T>
их в своем коде или увидел здесь некоторые ответы на сайте, которые используют span
- предположительно, какой-то контейнер. Но - я не могу найти ничего подобного в стандартной библиотеке C ++ 17.
Так что же это за таинственное span<T>
и почему (или когда) стоит использовать его, если оно нестандартно?
std::span
был предложен в 2017 году. Это относится к C ++ 17 или C ++ 20. Также см. P0122R5, span: безопасные для границ представления для последовательностей объектов . Вы действительно хотите нацелиться на этот язык? Пройдут годы, прежде чем компиляторы догонят.gsl::span
а не дляstd::span
. Смотрите также мой ответ ниже.Ответы:
Что это?
А
span<T>
это:T
где-то в памяти.struct { T * ptr; std::size_t length; }
с кучей удобных методов.Ранее он был известен как
array_view
и даже раньшеarray_ref
.Когда я должен использовать это?
Во-первых, когда его не использовать:
std::sort
,std::find_if
,std::copy
и все эти супер-родовое шаблонных функций.Теперь для того, когда фактически использовать это:
Почему я должен использовать это? Почему это хорошо?
Ох, промежутки потрясающие! Используя
span
...означает, что вы можете работать с этой комбинацией указатель + длина / начало + конец указателя, как если бы вы работали со сложным контейнером стандартной библиотеки, например:
for (auto& x : my_span) { /* do stuff */ }
std::find_if(my_span.begin(), my_span.end(), some_predicate);
... но без каких-либо накладных расходов большинство контейнерных классов.
позволяет компилятору иногда выполнять за вас больше работы. Например, это:
становится так:
... который будет делать то, что вы хотели бы это сделать. См. Также Рекомендацию P.5 .
является разумной альтернативой переходу
const vector<T>&
к функциям, когда вы ожидаете, что ваши данные будут непрерывными в памяти. Больше не надо ругать могучих гуру C ++!span
методы будут иметь некоторый код проверки границ внутри#ifndef NDEBUG
...#endif
)Есть еще больше мотивов для использования
span
s, которые вы можете найти в основных рекомендациях C ++ - но вы поймете, что это дрейф.Почему его нет в стандартной библиотеке (по состоянию на C ++ 17)?
Он есть в стандартной библиотеке - но только на C ++ 20. Причина в том, что он все еще довольно новый в своей нынешней форме, задуманный в связи с проектом основных рекомендаций C ++ , который формируется только с 2015 года. (Хотя, как отмечают комментаторы, он имеет более раннюю историю).
Так как мне его использовать, если его еще нет в стандартной библиотеке?
Это часть библиотеки поддержки основных руководящих принципов (GSL). Реализации:
gsl/span
span<T>
.Реализация GSL обычно предполагает платформу, которая реализует поддержку C ++ 14 [ 14 ]. Эти альтернативные реализации с одним заголовком не зависят от средств GSL:
martinmoene/span-lite
требуется C ++ 98 или более поздняя версияtcbrindle/span
требуется C ++ 11 или более поздняя версияОбратите внимание, что эти разные реализации span имеют некоторые различия в том, какие методы / вспомогательные функции они поставляют; и они также могут несколько отличаться от версии, входящей в стандартную библиотеку C ++ 20.
Дальнейшее чтение: Вы можете найти все детали и конструктивные соображения в окончательном официальном предложении до C ++ 17, P0122R7: span: безопасные для границ представления для последовательностей объектов Нила Макинтоша и Стефана Дж. Лававея. Это немного долго, хотя. Кроме того, в C ++ 20 изменилась семантика сравнения диапазонов (после этой короткой статьи Тони ван Эрда).
источник
std::cout << sizeof(buffer) << '\n'
и вы увидите, что вы получите 100 sizeof (int).std::array
- это контейнер, он владеет значениями.span
не владеетstd::array
это совершенно другой зверь. Как пояснил Калет, его длина фиксируется во время компиляции, и это тип значения, а не ссылочный тип.@einpoklum неплохо показывает, что
span
есть в его ответе . Тем не менее, даже после прочтения его ответа, для новичков в спанах будет легко иметь последовательность вопросов для обсуждения, на которые нет полного ответа, таких как следующее:span
отличается от массива C? Почему бы просто не использовать один из них? Похоже, что это только один из известных размеров ...std::array
, какspan
отличается от этого?std::vector
как уstd::array
тоже?span
?Итак, вот дополнительная ясность по этому поводу:
ПРЯМАЯ ЦИТАТА ЕГО ОТВЕТА - С МОИМИ ДОПОЛНЕНИЯМИ, выделенными жирным шрифтом :
Эти смелые части имеют решающее значение для понимания, так что не пропустите их или не прочитайте их! A
span
НЕ является C-массивом структур и не является структурой C-массива типаT
плюс длина массива (по сути, это будетstd::array
контейнер ), NOR это C-массив структур указателей. к типуT
плюс длина, но скорее это единственная структура, содержащая один единственный указатель на типT
, и длину , которая является количеством элементов (типаT
) в непрерывном блоке памяти, на которыйT
указывает указатель на тип ! Таким образом, единственные накладные расходы, которые вы добавили, используяspan
переменные для хранения указателя и длины, а также любые удобные функции доступа, которые вы используетеspan
.Это UNLIKE a,
std::array<>
потому чтоstd::array<>
фактически выделяет память для всего смежного блока, и это UNLIKE,std::vector<>
потому что astd::vector
в основном просто a,std::array
который также выполняет динамический рост (обычно удваивается в размере) каждый раз, когда он заполняется, и вы пытаетесь добавить что-то еще к нему , Astd::array
имеет фиксированный размер, и aspan
даже не управляет памятью блока, на который он указывает, он просто указывает на блок памяти, знает, как долго находится блок памяти, знает, какой тип данных находится в C-массиве в памяти, и предоставляет удобные функции доступа для работы с элементами в этой смежной памяти .Она является частью C ++ стандарт:
std::span
является частью стандарта C ++ с C ++ 20. Вы можете прочитать его документацию здесь: https://en.cppreference.com/w/cpp/container/span . Чтобы узнать , как использовать Google,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 или более поздней версии сегодня ?Google открыл свои внутренние библиотеки C ++ 11 в форме своей библиотеки «Abseil». Эта библиотека предназначена для обеспечения функций C ++ 14 - C ++ 20 и более, которые работают в C ++ 11 и более поздних версиях, так что вы можете использовать функции завтрашнего дня уже сегодня. Они говорят:
Вот некоторые ключевые ресурсы и ссылки:
span.h
заголовок иabsl::Span<T>(array, length)
класс шаблона: https://github.com/abseil/abseil-cpp/blob/master/absl/types/span.h#L189источник