Was ist der Unterschied zwischen a std::vector
und ein std::array
in C++? Wann sollte man einem anderen den Vorzug geben? Was sind die Vor- und Nachteile der einzelnen? Alles, was mein Lehrbuch tut, ist aufzulisten, wie sie gleich sind.
std::vector versus std::array in C++
Zud
Matteo Italien
std::vector
ist eine Vorlagenklasse, die ein dynamisches Array kapselt1, gespeichert im Heap, der automatisch wächst und schrumpft, wenn Elemente hinzugefügt oder entfernt werden. Es bietet alle Haken (begin()
, end()
, Iteratoren usw.), die dafür sorgen, dass es mit dem Rest der STL gut funktioniert. Es hat auch mehrere nützliche Methoden, mit denen Sie Operationen ausführen können, die auf einem normalen Array umständlich wären, wie zB das Einfügen von Elementen in der Mitte eines Vektors (es erledigt die ganze Arbeit des Verschiebens der folgenden Elemente im Hintergrund).
Da es die Elemente im auf dem Heap zugewiesenen Speicher speichert, hat es in Bezug auf statische Arrays einen gewissen Overhead.
std::array
ist eine Vorlagenklasse, die ein Array mit statischer Größe kapselt, das im Objekt selbst gespeichert ist. Wenn Sie also die Klasse auf dem Stack instanziieren, befindet sich das Array selbst auf dem Stack. Seine Größe muss zur Kompilierzeit bekannt sein (sie wird als Vorlagenparameter übergeben) und kann nicht wachsen oder schrumpfen.
Es ist begrenzter als std::vector
, aber es ist oft effizienter, besonders für kleine Größen, weil es in der Praxis meistens ein leichtgewichtiger Wrapper um ein Array im C-Stil ist. Es ist jedoch sicherer, da die implizite Konvertierung in einen Zeiger deaktiviert ist, und es bietet einen Großteil der STL-bezogenen Funktionalität von std::vector
und der anderen Container, sodass Sie es problemlos mit STL-Algorithmen & Co. verwenden können. Wie auch immer, für die Beschränkung auf eine feste Größe ist es viel weniger flexibel als std::vector
.
Zur Einführung in std::array
schau mal Dieser Beitrag; zum schnellen Einstieg std::vector
und zu den Operationen, die darauf möglich sind, möchten Sie vielleicht einen Blick darauf werfen Dokumentation.
Tatsächlich denke ich, dass sie im Standard in Bezug auf die maximale Komplexität der verschiedenen Operationen beschrieben werden (z. B. wahlfreier Zugriff in konstanter Zeit, Iteration über alle Elemente in linearer Zeit, Hinzufügen und Entfernen von Elementen am Ende in konstanter amortisierter Zeit, usw.), aber AFAIK gibt es keine andere Methode, um solche Anforderungen zu erfüllen, als ein dynamisches Array zu verwenden.Wie von @Lucretiel angegeben, erfordert der Standard tatsächlich, dass die Elemente zusammenhängend gespeichert werden, also es ist ein dynamisches Array, das dort gespeichert wird, wo der zugeordnete Allokator es ablegt.
-
Zu Ihrer Fußnote: Der Standard garantiert zwar, dass die Zeigerarithmetik auf den internen Elementen funktioniert, was bedeutet, dass es sich um ein Array handeln muss: &vec[9] – &vec[3] == 6 ist wahr.
– Lucretiel
12. März 2012 um 6:17 Uhr
-
Ich bin mir ziemlich sicher, dass dieser Vektor nicht automatisch schrumpft, aber seit C ++ 11 können Sie Shrink_to_fit aufrufen.
– Dino
9. September 2014 um 9:24 Uhr
-
Ich bin total verwirrt von dem Begriff statisches Array und ich bin mir nicht sicher, was die richtige Terminologie ist. Sie meinen ein Array mit statischer Größe und kein statisches Variablen-Array (eines mit statischem Speicher). stackoverflow.com/questions/2672085/…. Was ist die richtige Terminologie? Ist statisches Array ein schlampiger Begriff für ein Array mit fester Größe?
– Z-Boson
21. Oktober 2014 um 11:30 Uhr
-
@Zboson: es geht definitiv nicht nur dir so, statisch ist ein ziemlich missbrauchter Begriff; genau dieses
static
Das Schlüsselwort in C++ hat drei verschiedene, voneinander unabhängige Bedeutungen, und der Begriff wird auch oft verwendet, um über Dinge zu sprechen, die zur Kompilierzeit behoben werden. Ich hoffe, dass “statische Größe” etwas klarer ist.– Matteo Italien
21. Oktober 2014 um 12:55 Uhr
-
Eine Sache zu beachten: Für die Echtzeitprogrammierung (wo Sie nicht haben sollten irgendein dynamische Zuweisung/Aufhebung der Zuweisung nach dem Start) std::array wäre wahrscheinlich std::vector vorzuziehen.
– TED
13. Januar 2017 um 15:20 Uhr
Markus Lakata
Um einen Punkt von @MatteoItalia hervorzuheben: Der Effizienzunterschied besteht darin, wo die Daten gespeichert werden. Heap-Speicher (erforderlich bei vector
) erfordert einen Aufruf an das System, um Speicher zuzuweisen, und dies kann teuer werden, wenn Sie Zyklen zählen. Stapelspeicher (möglich für array
) ist praktisch “null Overhead” in Bezug auf die Zeit, da die Speicherzuweisung nur durch das Anpassen des Stapelzeigers erfolgt und dies nur einmal beim Aufrufen einer Funktion erfolgt. Der Stack vermeidet auch eine Speicherfragmentierung. Um sicher zu sein, std::array
wird nicht immer auf dem Stack sein; Es hängt davon ab, wo Sie es zuweisen, aber es wird immer noch eine Speicherzuweisung weniger vom Heap im Vergleich zum Vektor erforderlich sein. Wenn Sie eine haben
- kleines “Array” (sagen wir unter 100 Elementen) – (ein typischer Stack ist etwa 8 MB groß, weisen Sie dem Stack also nicht mehr als ein paar KB oder weniger zu, wenn Ihr Code rekursiv ist)
- Die Größe wird festgelegt
- Die Lebensdauer liegt im Funktionsbereich (oder ist ein Elementwert mit derselben Lebensdauer wie die übergeordnete Klasse).
- Du zählst Zyklen,
Verwenden Sie auf jeden Fall a std::array
über einen Vektor. Wenn eine dieser Anforderungen nicht zutrifft, verwenden Sie a std::vector
.
-
Gute Antwort. “Sicher, std::array wird nicht immer auf dem Stack sein; es hängt davon ab, wo Sie es zuweisen.” Wie könnte ich also ein std::array erstellen, das sich nicht auf dem Stack mit einer großen Anzahl von Elementen befindet?
– Trilarion
18. Januar 2017 um 9:45 Uhr
-
@ Trilarion verwenden
new std::array
oder machen Sie es zu einem Mitglied einer Klasse, die Sie mit “new” zuweisen.– Mark Lakata
18. Januar 2017 um 15:37 Uhr
-
Das bedeutet also
new std::array
Erwartet immer noch, seine Größe zur Kompilierzeit zu kennen und kann seine Größe nicht ändern, lebt aber immer noch auf dem Haufen?– Trilarion
18. Januar 2017 um 16:12 Uhr
-
Jawohl. Es gibt keinen wesentlichen Vorteil bei der Verwendung
new std::array
vsnew std::vector
.– Mark Lakata
18. Januar 2017 um 18:34 Uhr
SchließungCowboy
Verwendung der std::vector<T>
Klasse:
-
…ist genauso schnell wie bei der Verwendung integrierter Arrays, vorausgesetzt, Sie tun nur die Dinge, die Sie mit integrierten Arrays tun können (Lesen und Schreiben in vorhandene Elemente).
-
…ändert automatisch die Größe, wenn neue Elemente eingefügt werden.
-
…ermöglicht das Einfügen neuer Elemente am Anfang oder mitten drin des Vektors, wodurch die restlichen Elemente automatisch “nach oben” “verschoben” werden (macht das Sinn?). Es erlaubt Ihnen, Elemente überall in der zu entfernen
std::vector
wodurch die restlichen Elemente automatisch nach unten verschoben werden. -
…ermöglicht es Ihnen, einen bereichsgeprüften Lesevorgang mit dem durchzuführen
at()
Methode (Sie können immer die Indexer verwenden[]
wenn Sie diese Prüfung nicht wünschen).
Es gibt zwei drei Hauptvorbehalte zur Verwendung std::vector<T>
:
-
Sie haben keinen zuverlässigen Zugriff auf den zugrunde liegenden Zeiger, was dürfen ein Problem sein, wenn Sie es mit Funktionen von Drittanbietern zu tun haben, die die Adresse eines Arrays verlangen.
-
Die
std::vector<bool>
Klasse ist dumm. Es ist als komprimiertes Bitfeld implementiert, nicht als Array. Vermeiden Sie es, wenn Sie ein Array von möchtenbool
S! -
Während der Nutzung,
std::vector<T>
s werden etwas größer sein als ein C++-Array mit der gleichen Anzahl von Elementen. Dies liegt daran, dass sie eine kleine Menge anderer Informationen im Auge behalten müssen, z. B. ihre aktuelle Größe und wann immer sie möchtenstd::vector<T>
s Größe ändern, reservieren sie mehr Platz, als sie benötigen. Dies soll verhindern, dass sie jedes Mal die Größe ändern müssen, wenn ein neues Element eingefügt wird. Dieses Verhalten kann durch Bereitstellung einer benutzerdefinierten geändert werdenallocator
aber ich hatte nie das Bedürfnis, das zu tun!
Bearbeiten: Nachdem ich Zuds Antwort auf die Frage gelesen hatte, hatte ich das Gefühl, ich sollte Folgendes hinzufügen:
Die std::array<T>
class ist nicht dasselbe wie ein C++-Array. std::array<T>
ist ein sehr dünner Wrapper um C++-Arrays mit dem Hauptzweck, den Zeiger vor dem Benutzer der Klasse zu verbergen (in C++ werden Arrays implizit als Zeiger umgewandelt, oft mit erschreckender Wirkung). Die std::array<T>
Klasse speichert auch ihre Größe (Länge), was sehr nützlich sein kann.
-
Es ist “genauso schnell” wie die Verwendung eines dynamisch zugewiesenen integrierten Arrays. Andererseits kann die Verwendung eines automatischen Arrays eine erheblich unterschiedliche Leistung haben (und nicht nur während der Zuweisung aufgrund von Lokalitätseffekten).
– Ben Voigt
27. August 2013 um 18:13 Uhr
-
Für Nicht-Bool-Vektoren in C++11 und höher können Sie aufrufen
data()
auf einenstd::vector<T>
um den zugrunde liegenden Zeiger zu erhalten. Sie können auch einfach die Adresse von Element 0 nehmen (funktioniert garantiert mit C++11, wird wahrscheinlich mit früheren Versionen funktionieren).– Matt
25. Juni 2015 um 18:01 Uhr
-
Im letzten Absatz meinst du C-Array? Rechts ?
– Tanishq-Banyal
18. Juni 2021 um 8:53 Uhr
Wenn Sie mehrdimensionale Arrays verwenden möchten, gibt es einen zusätzlichen Unterschied zwischen std::array und std::vector. Bei einem mehrdimensionalen std::array werden die Elemente in allen Dimensionen im Speicher gepackt, genau wie bei einem Array im ac-Stil. Ein multidimensionaler std::vector wird nicht in alle Dimensionen gepackt.
Angesichts der folgenden Erklärungen:
int cConc[3][5];
std::array<std::array<int, 5>, 3> aConc;
int **ptrConc; // initialized to [3][5] via new and destructed via delete
std::vector<std::vector<int>> vConc; // initialized to [3][5]
Ein Zeiger auf das erste Element im Array im c-Stil (cConc) oder im std::array (aConc) kann durch das gesamte Array iteriert werden, indem jedem vorangehenden Element eine 1 hinzugefügt wird. Sie sind dicht gepackt.
Ein Zeiger auf das erste Element im Vektorarray (vConc) oder im Zeigerarray (ptrConc) kann nur durch die ersten 5 (in diesem Fall) Elemente iteriert werden, und dann gibt es 12 Bytes (auf meinem System) Overhead für die nächster Vektor.
Dies bedeutet, dass ein std::vector> Array als initialisiert wird [3][1000] Das Array wird im Speicher viel kleiner sein als eines, das als a initialisiert wird [1000][3] array, und beide haben einen größeren Arbeitsspeicher als ein std:array, das so oder so zugewiesen wurde.
Das bedeutet auch, dass Sie nicht einfach ein mehrdimensionales Vektor- (oder Zeiger-) Array an OpenGL übergeben können, ohne den Speicheraufwand zu berücksichtigen, aber Sie können naiv ein mehrdimensionales std::array an OpenGL übergeben und es funktioniert.
Fassen Sie die obige Diskussion in einer Tabelle zum schnellen Nachschlagen zusammen:
Array im C-Stil | std::array | std::Vektor | |
---|---|---|---|
Größe | Fest/Statisch | Fest/Statisch | Dynamisch |
Speichereffizienz | Effizienter | Effizienter | Weniger effizient (Kann seine Größe bei einer neuen Zuweisung verdoppeln.) |
Kopieren | Über Elemente iterieren oder std::copy() verwenden |
Direkte Kopie: a2 = a1; | Direktkopie: v2 = v1; |
Übergang zur Funktion | Zeiger übergeben. (Größe nicht in Funktion verfügbar) |
Wert übergeben | Wert übergeben (Größe in dieser Funktion verfügbar) |
Größe | Größe von (a1) / Größe von (a1[0]) | a1.Größe() | v1.size() |
Anwendungsfall | Für schnellen Zugriff und wann Einfügungen/Löschungen werden nicht häufig benötigt. |
Gleich wie klassisches Array, aber sicherer und einfacher zu übergeben und zu kopieren. |
Bei häufigen Ergänzungen bzw Löschungen könnten erforderlich sein |
-
void foo(T (& arr)[N])
würde die Array-Größe erfassen. ähnliche Magic-Arguments-in-Function-Templates– I.Omar
14. November 2021 um 18:22 Uhr
-
Ich würde diese Zeilen hinzufügen: “| Wertesemantik | nein | ja | ja |” und “| Move | O(N) | O(N) | O(1) |” und “| Vertausche | O(N) | O(N) | O(1) |”
– alfC
1. Februar um 19:11 Uhr
Saif al-Harthi
Ein Vektor ist eine Containerklasse, während ein Array ein zugewiesener Speicher ist.
-
void foo(T (& arr)[N])
würde die Array-Größe erfassen. ähnliche Magic-Arguments-in-Function-Templates– I.Omar
14. November 2021 um 18:22 Uhr
-
Ich würde diese Zeilen hinzufügen: “| Wertesemantik | nein | ja | ja |” und “| Move | O(N) | O(N) | O(1) |” und “| Vertausche | O(N) | O(N) | O(1) |”
– alfC
1. Februar um 19:11 Uhr
Ich suche einen Vergleich z
std::vector
vs.std::array
und wie sich die Begriffe unterscheiden.– Zud
12. Dezember 2010 um 23:02 Uhr
Zud,
std::array
ist nicht dasselbe wie ein C++-Array.std::array
ist ein sehr dünner Wrapper um C++-Arrays mit dem Hauptzweck, den Zeiger vor dem Benutzer der Klasse zu verbergen. Ich werde meine Antwort aktualisieren.– SchließungCowboy
12. Dezember 2010 um 23:19 Uhr
Ich habe den Titel und den Text der Frage aktualisiert, um Ihre Klarstellung widerzuspiegeln.
– Matteo Italien
12. Dezember 2010 um 23:32 Uhr
Wenn Sie die Funktion constexpr oder consteval implementieren, können Sie std::array verwenden, aber nicht std::vector. stackoverflow.com/questions/33241909/…
– Anton Krug
10. April 2021 um 16:48 Uhr