Ostatnio dostałem sugestie dotyczące użycia span<T>
w moim kodzie lub widziałem tutaj odpowiedzi na stronie, które używają span
- podobno jakiegoś kontenera. Ale - nie mogę znaleźć czegoś takiego w standardowej bibliotece C ++ 17.
Czym jest to tajemnicze span<T>
i dlaczego (lub kiedy) warto go używać, jeśli jest niestandardowy?
std::span
został zaproponowany w 2017 r. Dotyczy C ++ 17 lub C ++ 20. Zobacz także P0122R5, span: bezpieczne widoki dla sekwencji obiektów . Czy naprawdę chcesz kierować na ten język? Miną lata, zanim kompilatory nadrobią zaległości.gsl::span
zamiaststd::span
. Zobacz także moją odpowiedź poniżej.Odpowiedzi:
Co to jest?
A
span<T>
to:T
gdzieś w pamięci.struct { T * ptr; std::size_t length; }
z wieloma wygodnymi metodami.Wcześniej był znany jako,
array_view
a jeszcze wcześniej jakoarray_ref
.Kiedy powinienem go użyć?
Po pierwsze, kiedy go nie używać:
std::sort
,std::find_if
,std::copy
i wszystkich tych funkcji na matrycy Super-generic.Teraz, kiedy go używać:
Dlaczego powinienem tego używać? Dlaczego to dobrze?
Och, rozpiętości są niesamowite! Korzystanie z
span
...oznacza, że możesz pracować z tą kombinacją wskaźnika + długości / początku + końca, tak jak w przypadku fantazyjnego, wypchanego standardowego kontenera biblioteki, np .:
for (auto& x : my_span) { /* do stuff */ }
std::find_if(my_span.begin(), my_span.end(), some_predicate);
... ale absolutnie żadna z ogólnych kosztów, jakie ponosi większość klas kontenerów.
pozwala czasami kompilatorowi wykonać więcej pracy. Na przykład:
staje się to:
... który zrobi to, co chcesz. Zobacz także wytyczną P.5 .
jest rozsądną alternatywą dla przekazywania
const vector<T>&
do funkcji, gdy oczekuje się, że dane będą ciągłe w pamięci. Nigdy więcej besztany przez potężnych guru C ++!span
metody będą miały kod sprawdzający ograniczenia w#ifndef NDEBUG
...#endif
)Jest jeszcze więcej motywacji do używania
span
s, co można znaleźć w podstawowych wytycznych C ++ - ale łapiesz dryf.Dlaczego nie ma go w standardowej bibliotece (od C ++ 17)?
Jest w standardowej bibliotece - ale tylko od C ++ 20. Powodem jest to, że wciąż jest całkiem nowy w swojej obecnej formie, opracowanej w połączeniu z projektem głównych wytycznych C ++ , który kształtuje się dopiero od 2015 r. (Chociaż, jak podkreślają komentatorzy, ma wcześniejszą historię).
Jak więc go użyć, jeśli nie ma go jeszcze w standardowej bibliotece?
Jest częścią Biblioteki wsparcia podstawowych wytycznych (GSL). Realizacje:
gsl/span
span<T>
.Implementacja GSL zasadniczo zakłada platformę, która implementuje obsługę C ++ 14 [ 14 ]. Te alternatywne implementacje z jednym nagłówkiem nie zależą od funkcji GSL:
martinmoene/span-lite
wymaga C ++ 98 lub nowszegotcbrindle/span
wymaga C ++ 11 lub nowszegoZauważ, że te różne implementacje zakresu mają pewne różnice w tym, z jakimi metodami / funkcjami wsparcia pochodzą. i mogą się nieco różnić od wersji wchodzącej do standardowej biblioteki w C ++ 20.
Dalsza lektura: Wszystkie szczegóły i rozważania projektowe można znaleźć w ostatecznej oficjalnej propozycji przed C ++ 17, P0122R7: span: bezpieczne dla sekwencji widoki obiektów Neala Macintosha i Stephana J. Lavaveja. Trochę to jednak trwa. Również w C ++ 20 zmieniła się semantyka porównania rozpiętości (po tym krótkim artykule Tony van Eerda).
źródło
std::cout << sizeof(buffer) << '\n'
a zobaczysz, że masz 100 sizeof (int).std::array
jest kontenerem, posiada wartości.span
nie jest właścicielemstd::array
jest zupełnie inną bestią. Jego długość jest ustalona w czasie kompilacji i jest to typ wartości, a nie typ odniesienia, jak wyjaśnił Caleth.@einpoklum ma całkiem niezłą robotę, przedstawiając to, co
span
jest w swojej odpowiedzi tutaj . Jednak nawet po przeczytaniu jego odpowiedzi łatwo jest komuś nowemu, aby nadal miał sekwencję pytań, na które nie ma pełnej odpowiedzi, na przykład:span
różni się od tablicy C? Dlaczego nie skorzystać z jednego z nich? Wygląda na to, że to tylko jeden ze znanych rozmiarów ...std::array
, czym sięspan
różni od tego?std::vector
niczymstd::array
zbyt?span
?Oto kilka dodatkowych wyjaśnień na ten temat:
BEZPOŚREDNI WYCENA JEGO ODPOWIEDZI - Z MOIMMI DODATKAMI :
Te odważne części są kluczowe dla zrozumienia, więc nie przegap ich ani nie odczytaj ich źle! A
span
NIE jest tablicą C struktur, ani nie jest strukturą typu CT
powiększoną o długość tablicy (byłby to w zasadziestd::array
kontener ), NOR jest to tablica C struktur wskaźników pisaćT
plus długość, ale raczej jest to pojedyncza struktura zawierająca pojedynczy wskaźnik do pisaniaT
oraz długość , która jest liczbą elementów (typuT
) w ciągłym bloku pamięci, na któryT
wskazuje wskaźnik do pisania ! W ten sposób jedyny narzut dodany przy użyciuspan
to zmienne do przechowywania wskaźnika i długości oraz wszelkie używane funkcje akcesoriów, którespan
udostępnia.Jest to w przeciwieństwie do
std::array<>
, ponieważstd::array<>
rzeczywiście alokuje pamięć dla całego ciągły blok, a to jest podobnastd::vector<>
, ponieważstd::vector
jest w zasadzie tylkostd::array
, że również ma dynamiczny rośnie (zazwyczaj podwojenie wielkości) za każdym razem zapełnia się i spróbować dodać coś jeszcze do niego . Astd::array
ma stały rozmiar, a aspan
nawet nie zarządza pamięcią bloku, na który wskazuje, po prostu wskazuje blok pamięci, wie, jak długi jest blok pamięci, wie, jaki typ danych znajduje się w macierzy C. w pamięci i zapewnia dodatkowe funkcje akcesorium do pracy z elementami w tej ciągłej pamięci .To jest część C ++ standard:
std::span
jest częścią standardu C ++ od C ++ 20. Możesz przeczytać jego dokumentację tutaj: https://en.cppreference.com/w/cpp/container/span . Aby zobaczyć, jak korzystać z Googleabsl::Span<T>(array, length)
w C ++ 11 lub później dzisiaj , patrz poniżej.Opisy podsumowań i najważniejsze odniesienia:
std::span<T, Extent>
(Extent
= "liczba elementów w sekwencji lubstd::dynamic_extent
dynamiczna". Rozpiętość wskazuje tylko na pamięć i ułatwia dostęp, ale NIE zarządza nią!):std::array<T, N>
(zauważ, że ma ustalony rozmiarN
!):std::vector<T>
(automatycznie dynamicznie rośnie w miarę potrzeb):Jak mogę użyć
span
w C ++ 11 lub później dzisiaj ?Google ma otwarte źródła wewnętrznych bibliotek C ++ 11 w formie biblioteki „Abseil”. Ta biblioteka ma na celu dostarczanie funkcji od C ++ 14 do C ++ 20 i innych, które działają w C ++ 11 i późniejszych, abyś mógł dziś korzystać z funkcji jutra. Mówią:
Oto niektóre kluczowe zasoby i linki:
span.h
nagłówek iabsl::Span<T>(array, length)
klasa szablonów: https://github.com/abseil/abseil-cpp/blob/master/absl/types/span.h#L189źródło