2010-12-12 11 views
208

Was sind die Unterschiede zwischen einer std::vector und einer in C++? Wann sollte man einem anderen vorgezogen werden? Was sind die Vor- und Nachteile von jedem? All mein Lehrbuch führt auf, wie sie gleich sind.std :: Vektor im Vergleich zu std :: Array in C++

+1

Ich suche nach einem Vergleich von 'std :: vector' vs. 'std :: array' und wie die Begriffe unterschiedlich sind. – Zud

+0

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 vom Benutzer der Klasse zu verbergen. Ich werde meine Antwort aktualisieren. – ClosureCowboy

+0

Ich habe den Titel und den Text der Frage aktualisiert, um Ihre Klarstellung zu verdeutlichen. –

Antwort

235

std::vector ist eine Template-Klasse, die ein dynamisches Array , gespeichert in dem Haufen einzukapseln, dass wächst und schrumpft, wenn Elemente automatisch oder entfernt werden hinzugefügt. Es bietet alle Haken (begin(), end(), Iteratoren, etc.), die es mit dem Rest der STL gut funktionieren. Es hat auch mehrere nützliche Methoden, mit denen Sie Operationen ausführen können, die auf einem normalen Array mühsam wären, wie z.B. Einfügen von Elementen in der Mitte eines Vektors (es behandelt die ganze Arbeit der Bewegung der folgenden Elemente hinter den Kulissen).

Da es die Elemente im Arbeitsspeicher speichert, die auf dem Heap zugeordnet sind, hat es einige Overhead in Bezug auf statische Arrays.

ist eine Schablonenklasse, die ein Array 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 Stapel. Seine Größe muss zur Kompilierungszeit bekannt sein (sie wurde als Vorlagenparameter übergeben) und kann nicht vergrößert oder verkleinert werden.

Es ist begrenzter als std::vector, aber es ist oft effizienter, vor allem für kleine Größen, weil es in der Praxis meist ein leichter Wrapper um ein C-artiges Array ist. Es ist jedoch sicherer, da die implizite Konvertierung in Zeiger deaktiviert ist, und es bietet einen Großteil der STL-Funktionalität von std::vector und der anderen Container, so dass Sie es problemlos mit STL-Algorithmen & co verwenden können. Wie auch immer, für die Begrenzung der festen Größe ist es viel weniger flexibel als std::vector.

Für eine Einführung in std::array, sehen Sie sich this article; Für eine schnelle Einführung zu std::vector und zu den Operationen, die darauf möglich sind, können Sie sich die documentation ansehen.


  1. Eigentlich, denke ich, dass in der Standard, den sie in Bezug auf die maximale Komplexität der verschiedenen Operationen (zB Random Access in konstanter Zeit, Iteration über alle Elemente in linearer Zeit beschrieben werden, hinzufügen und Entfernen von Elementen am Ende in konstanter amortisierter Zeit, usw.), aber AFAIK gibt es keine andere Methode, diese Anforderungen zu erfüllen, als ein dynamisches Array zu verwenden. Wie von @ Lucectiel angegeben, erfordert der Standard tatsächlich, dass die Elemente zusammenhängend gespeichert werden, so ist es ein dynamisches Array, wo der zugeordnete Zuordner es speichert.
+5

In Bezug auf Ihre Fußnote: Obwohl das stimmt, garantiert der Standard auch, dass Zeigerarithmetik auf den internen Elementen funktioniert, was bedeutet, dass es ein Array sein muss: & vec [9] - & vec [3] == 6 ist wahr. – Lucretiel

+5

Ich bin mir ziemlich sicher, dass der Vektor nicht automatisch schrumpft, aber seit C++ 11 kann man shrink_to_fit aufrufen. – Dino

+0

Ich bin total verwirrt durch den Begriff _static array_ und ich bin mir nicht sicher, was die richtige Terminologie ist. Sie meinen ein Array mit statischer Größe und nicht ein Array mit statischen Variablen (eines mit statischem Speicher). https://stackoverflow.com/questions/2672085/c-static-array-vs-dynamic-array/26466627#26466627. Was ist die korrekte Terminologie? Ist das statische Array ein schlampiger Begriff für ein Array mit einer festen Größe? –

-13

Ein Vektor ist eine Container-Klasse, während ein Array ein zugewiesener Speicher ist.

+12

Ihre Antwort scheint zu adressieren 'std :: vector ' versus 'T []', aber die Frage ist über 'std :: vector ' versus 'std :: array '. –

13

Mit der std::vector<T> Klasse:

  • ... ist genauso schnell als Einbau-Arrays verwenden, können Sie unter der Annahme, nur die Dinge, Einbau-Arrays tun können Sie tun (Lesen und Schreiben in vorhandene Elemente).

  • ... wird automatisch angepasst, wenn neue Elemente eingefügt werden.

  • ... können Sie neue Elemente am Anfang oder in der Mitte des Vektors eingefügt werden, automatisch den Rest der Elemente „nach oben“ „Verschiebung“ (Macht das Sinn?). Es ermöglicht Ihnen, Elemente überall in der std::vector auch zu entfernen, automatisch den Rest der Elemente nach unten verschieben.

  • ... können Sie einen bereichsüberprüften Lesevorgang mit der Methode at() durchführen (Sie können immer die Indexer [] verwenden, wenn diese Überprüfung nicht durchgeführt werden soll).

Es gibt zwei drei Einsprüche zur Verwendung von std::vector<T>:

  1. Sie haben keine zuverlässigen Zugriff auf die zugrunde liegende Zeiger haben, die kann ein Problem sein, wenn Sie es zu tun Funktionen von Drittanbietern, die die Adresse eines Arrays anfordern.

  2. Die std::vector<bool> Klasse ist albern. Es ist als ein kondensiertes Bitfeld implementiert, nicht als ein Array. Vermeiden Sie es, wenn Sie ein Array von bool s möchten!

  3. Während der Verwendung werden std::vector<T> s ein bisschen größer als ein C++ - Array mit der gleichen Anzahl von Elementen sein. Dies liegt daran, dass sie eine kleine Menge anderer Informationen verfolgen müssen, z. B. ihre aktuelle Größe, und weil sie bei einer Größenänderung von std::vector<T> immer mehr Speicherplatz reservieren, als sie benötigen. Dies soll verhindern, dass sie jedes Mal, wenn ein neues Element eingefügt wird, die Größe ändern müssen. Dieses Verhalten kann durch eine benutzerdefinierte allocator geändert werden, aber ich habe nie das Bedürfnis, dies zu tun!


Edit: Nach Zud Antwort auf die Frage zu lesen, fühlte ich, sollte ich hinzufügen:

Die std::array<T> Klasse nicht das gleiche wie eine C++ Array ist. std::array<T> ist eine sehr dünne Wrapper um C++ - Arrays, mit dem Hauptzweck, den Zeiger vom Benutzer der Klasse zu verstecken (in C++ werden Arrays implizit als Zeiger, oft zum Schreckenseffekt umgewandelt). Die Klasse std::array<T> speichert auch ihre Größe (Länge), was sehr nützlich sein kann.

+4

Es ist "genauso schnell" wie die Verwendung eines dynamisch zugewiesenen integrierten Arrays. Andererseits kann die Verwendung eines automatischen Arrays eine erheblich andere Leistung haben (und nicht nur während der Zuweisung aufgrund von Lokalitätseffekten.) –

+2

Für nicht bool Vektoren in C++ 11 und später können Sie 'data()' auf einem 'std :: vector ' aufrufen, um den zugrunde liegenden Zeiger zu erhalten.Sie können auch einfach die Adresse von Element 0 nehmen (garantiert mit C++ zu arbeiten 11, wird wahrscheinlich mit früheren Versionen arbeiten. – Matt

-12

Einer der Vorteile, die Vektoren über Arrays ist, dass es möglich ist, die aktuelle Größe eines Vektors unter Verwendung vector_name.size() zu finden.

Wie Sie sich vorstellen können, kann dies in einer Vielzahl von Situationen sehr nützlich sein, in denen Sie die Anzahl der Elemente in der array_list einfach abrufen können.

+10

Sie können das auch mit std :: array tun – Gerard

10

Um einen Punkt hervorzuheben, der von @MatteoItalia gemacht wurde, ist der Effizienzunterschied der Ort, an dem die Daten gespeichert werden. Der Heap-Speicher (erforderlich mit vector) erfordert einen Aufruf an das System, um Speicher zuzuweisen, und dies kann teuer sein, wenn Sie Zyklen zählen. Stack-Speicher (möglich für array) ist praktisch "null Overhead" in Bezug auf die Zeit, weil der Speicher nur durch Einstellen des Stack-Pointers zugewiesen wird und es nur einmal beim Eintritt in eine Funktion getan wird. Der Stapel vermeidet auch eine Speicherfragmentierung.Um sicher zu sein, wird nicht immer auf dem Stapel sein; Es hängt davon ab, wo Sie es zuweisen, aber es wird immer noch eine Speicherzuweisung weniger von dem Heap im Vergleich zu Vektor enthalten. Wenn Sie einen

  • kleinen „Array“ (unter 100 Elemente sagen) - (ein typischer Stapel ist etwa 8 MB, also nicht zuteile nicht mehr als ein paar KB auf dem Stack oder weniger, wenn Ihr Code rekursiv)
  • wird die Größe
  • die Lebensdauer ist im Funktionsumfang festgelegt werden (oder ein Mitglied Wert mit der gleichen Lebensdauer wie die übergeordneten Klasse)
  • Sie zählen Zyklen,

definitiv verwenden std::array über einen Vektor. Wenn eine dieser Anforderungen nicht zutrifft, verwenden Sie eine std::vector.

+3

Schöne Antwort. "Um sicher zu sein, wird std :: array nicht immer auf dem Stapel sein; es hängt davon ab, wo Sie es zuweisen "So wie könnte ich ein std :: Array nicht auf dem Stapel mit einer großen Anzahl von Elementen erstellen? – Trilarion

+3

@Trilarion verwenden' neue std :: array' oder machen Sie es zu einem Mitglied der Klasse, die Sie Verwenden Sie "new" um zu reservieren –

+0

Dies bedeutet, dass "new std :: array" immer noch erwartet seine Größe zur Kompilierzeit zu kennen und seine Größe nicht ändern kann, aber immer noch auf dem Heap lebt? – Trilarion

6

Wenn Sie mehrdimensionale Arrays verwenden, gibt es einen weiteren Unterschied zwischen std :: array und std :: vector. In einem mehrdimensionalen std :: -Array werden die Elemente in allen Dimensionen gespeichert, genau wie bei einem c-array. Ein mehrdimensionaler std :: vector wird nicht in allen 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 in der c-style-Array (cConc) oder der std :: array (aConc) kann durch Zugabe von 1 über das gesamte Array wiederholt werden zu jedem vorhergehenden Element. Sie sind dicht gepackt.

Ein Zeiger auf das erste Element im Vektor-Array (vConc) oder das Zeiger-Array (ptrConc) kann nur durch die ersten 5 (in diesem Fall) Elemente durchlaufen werden, und dann gibt es 12 Bytes (auf meinem System) Overhead für den nächsten Vektor.

Dies bedeutet, dass ein als Array [3] [1000] initialisiertes Array std :: vector> viel kleiner im Speicher ist als eines, das als Array [1000] [3] initialisiert wurde und beide Speicher größer sind als ein std: Array, das in beide Richtungen zugewiesen ist. Das bedeutet auch, dass Sie ein multidimensionales Vektorarray (oder Zeigerarray) nicht einfach 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 haben trainieren.