Kürzlich habe ich Vorschläge zur Verwendung von span<T>
's in meinem Code erhalten oder hier auf der Website einige Antworten gesehen, die span
' s 'verwenden - angeblich eine Art Container. Aber - ich kann so etwas in der C ++ 17-Standardbibliothek nicht finden.
Was ist das mysteriös span<T>
und warum (oder wann) ist es eine gute Idee, es zu verwenden, wenn es nicht dem Standard entspricht?
std::span
wurde 2017 vorgeschlagen. Es gilt für C ++ 17 oder C ++ 20. Siehe auch P0122R5, span: Grenzen-sichere Ansichten für Sequenzen von Objekten . Möchten Sie diese Sprache wirklich ansprechen? Es wird Jahre dauern, bis die Compiler aufholen.gsl::span
eherstd::span
. Siehe auch meine Antwort unten.Antworten:
Was ist es?
A
span<T>
ist:T
irgendwo im Speicher.struct { T * ptr; std::size_t length; }
mit einer Reihe von praktischen Methoden.Es war früher als
array_view
und noch früher als bekanntarray_ref
.Wann soll ich es benutzen?
Erstens, wenn Sie es nicht verwenden sollten:
std::sort
,std::find_if
,std::copy
und all diese super-generische Template - Funktionen.Nun, wann Sie es tatsächlich verwenden sollten:
Warum sollte ich es benutzen? Warum ist es eine gute Sache?
Oh, Spannweiten sind großartig! Verwenden eines
span
...bedeutet, dass Sie mit dieser Kombination aus Zeiger + Länge / Start + Endezeiger wie mit einem ausgefallenen, aufgemotzten Standardbibliothekscontainer arbeiten können, z.
for (auto& x : my_span) { /* do stuff */ }
std::find_if(my_span.begin(), my_span.end(), some_predicate);
... aber mit absolut keinem Overhead fallen die meisten Containerklassen an.
Der Compiler erledigt manchmal mehr Arbeit für Sie. Zum Beispiel:
wird dies:
... was tun wird, was Sie möchten. Siehe auch Richtlinie S.5 .
ist die sinnvolle Alternative zur Übergabe
const vector<T>&
an Funktionen, wenn Sie erwarten, dass Ihre Daten im Speicher zusammenhängend sind. Nie mehr von hochmächtigen C ++ - Gurus beschimpft werden!span
die Methoden enthalten einen Code zur Überprüfung der Grenzen in#ifndef NDEBUG
...#endif
)Es gibt noch mehr Motivation für die Verwendung von
span
s, die Sie in den C ++ - Kernrichtlinien finden können - aber Sie verstehen die Abweichung.Warum ist es nicht in der Standardbibliothek (ab C ++ 17)?
Es befindet sich in der Standardbibliothek - jedoch nur ab C ++ 20. Der Grund dafür ist, dass es in seiner aktuellen Form noch ziemlich neu ist und in Verbindung mit dem C ++ - Kernrichtlinienprojekt konzipiert wurde , das erst seit 2015 Gestalt annimmt. (Obwohl es, wie Kommentatoren betonen, eine frühere Geschichte hat.)
Wie verwende ich es, wenn es noch nicht in der Standardbibliothek enthalten ist?
Es ist Teil der Support Library (GSL) der Core Guidelines . Implementierungen:
gsl/span
span<T>
.Die GSL-Implementierung setzt im Allgemeinen eine Plattform voraus, die die C ++ 14-Unterstützung implementiert [ 14 ]. Diese alternativen Einzelheader-Implementierungen hängen nicht von GSL-Einrichtungen ab:
martinmoene/span-lite
erfordert C ++ 98 oder höhertcbrindle/span
erfordert C ++ 11 oder höherBeachten Sie, dass diese verschiedenen Span-Implementierungen einige Unterschiede in den Methoden / Unterstützungsfunktionen aufweisen, mit denen sie geliefert werden. und sie können sich auch etwas von der Version unterscheiden, die in die Standardbibliothek in C ++ 20 aufgenommen wurde.
Weiterführende Literatur: Alle Details und Entwurfsüberlegungen finden Sie im endgültigen offiziellen Vorschlag vor C ++ 17, P0122R7: span: Grenzen-sichere Ansichten für Objektsequenzen von Neal Macintosh und Stephan J. Lavavej. Es ist allerdings etwas lang. Außerdem hat sich in C ++ 20 die Semantik des Bereichsvergleichs geändert (nach diesem kurzen Artikel von Tony van Eerd).
quelle
std::cout << sizeof(buffer) << '\n'
und Sie werden sehen, dass Sie 100 sizeof (int) erhalten.std::array
ist ein Container, dem die Werte gehören.span
ist nicht im Besitzstd::array
ist ein ganz anderes Tier. Seine Länge ist zur Kompilierungszeit festgelegt und es handelt sich eher um einen Werttyp als um einen Referenztyp, wie Caleth erklärte.@einpoklum hat einen ziemlich guten Job einzuführen , was eine
span
ist hier in seiner Antwort . Doch auch nach seiner Antwort zu lesen, ist es einfach für jemanden neu in Spannweiten noch eine Folge von Stream-of-Gedanken Fragen hat , die nicht vollständig beantwortet werden, wie die folgenden:span
unterscheidet sich ein C-Array? Warum nicht einfach eine davon verwenden? Es scheint, als wäre es nur einer von denen mit der bekannten Größe ...std::array
, wie unterscheidet sich einspan
davon?std::vector
wie einstd::array
zu?span
?Hier ist eine zusätzliche Klarheit dazu:
DIREKTES ZITAT SEINER ANTWORT - MIT MEINEN ERGÄNZUNGEN IN Fettdruck :
Diese fett Teile sind kritisch zu einem Verständnis, also nicht verpassen sie oder sie falsch verstanden! A
span
ist KEIN C-Array von Strukturen, noch ist es eine Struktur eines C-Arrays vom TypT
plus der Länge des Arrays (dies wäre im Wesentlichen das, was derstd::array
Container ist), NOR ist es ein C-Array von Strukturen von Zeigern zu tippenT
plus die Länge, sondern es ist eine einzelne Struktur, die einen einzelnen zuT
tippenden Zeiger enthält , und die Länge , die die Anzahl der Elemente (vom TypT
) in dem zusammenhängenden Speicherblock ist, auf den der zu tippende ZeigerT
zeigt! Auf diese Weise erhalten Sie den einzigen Overhead, den Sie mithilfe von a hinzugefügt habenspan
sind die Variablen zum Speichern des Zeigers und der Länge sowie alle von Ihnen verwendeten praktischen Zugriffsfunktionenspan
.Dies ist im Gegensatz zu einem ,
std::array<>
weil diestd::array<>
tatsächlich zuteilt Speicher für den gesamten zusammenhängenden Block, und es ist nicht wie,std::vector<>
weil einstd::vector
im Grunde ist eine gerade ,std::array
dass auch tut dynamisch wachsen ( in der Regel in der Größe verdoppelt) jedes Mal , es füllt sich , und Sie versuchen , etwas anderes , um es hinzuzufügen . Astd::array
hat eine feste Größe und aspan
verwaltet nicht einmal den Speicher des Blocks, auf den es zeigt. Es zeigt nur auf den Speicherblock, weiß, wie lang der Speicherblock ist und weiß, welcher Datentyp in einem C-Array enthalten ist im Speicher und bietet praktische Zugriffsfunktionen, um mit den Elementen in diesem zusammenhängenden Speicher zu arbeiten .Es ist Teil des C ++ - Standards:
std::span
ist Teil des C ++ - Standards ab C ++ 20. Sie können die Dokumentation hier lesen: https://en.cppreference.com/w/cpp/container/span . Informationen zur Verwendung von Googleabsl::Span<T>(array, length)
in C ++ 11 oder höher finden Sie weiter unten.Zusammenfassende Beschreibungen und wichtige Referenzen:
std::span<T, Extent>
(Extent
= "die Anzahl der Elemente in der Sequenz oderstd::dynamic_extent
wenn dynamisch". Ein Bereich zeigt nur auf den Speicher und erleichtert den Zugriff, verwaltet ihn jedoch NICHT!):std::array<T, N>
(Beachten Sie, dass es eine feste Größe hatN
!):std::vector<T>
(wächst bei Bedarf automatisch dynamisch an Größe):Wie kann ich
span
in C ++ 11 oder später heute ?Google hat seine internen C ++ 11-Bibliotheken in Form seiner "Abseil" -Bibliothek als Open-Source-Version bereitgestellt. Diese Bibliothek soll Funktionen von C ++ 14 bis C ++ 20 und darüber hinaus bereitstellen, die in C ++ 11 und höher funktionieren, sodass Sie die Funktionen von morgen noch heute nutzen können. Man sagt:
Hier sind einige wichtige Ressourcen und Links:
span.h
Header undabsl::Span<T>(array, length)
Vorlagenklasse: https://github.com/abseil/abseil-cpp/blob/master/absl/types/span.h#L189quelle