it-swarm.com.de

In welchem ​​Szenario verwende ich einen bestimmten STL-Container?

Ich habe in meinem Buch zu C++ über STL-Container gelesen, insbesondere über die STL und ihre Container. Jetzt verstehe ich, dass jeder von ihnen seine eigenen spezifischen Eigenschaften hat, und ich bin kurz davor, sie alle auswendig zu lernen. Aber was ich noch nicht verstehe, ist, in welchem ​​Szenario jeder von ihnen verwendet wird.

Was ist die Erklärung? Beispielcode wird sehr bevorzugt.

170
Daniel Sloof

Dieser Spickzettel bietet eine ziemlich gute Zusammenfassung der verschiedenen Container.

Sehen Sie sich das Flussdiagramm unten an, um Informationen für verschiedene Anwendungsszenarien zu erhalten:

http://linuxsoftware.co.nz/containerchoice.png

Erstellt von David Moore und lizenziert CC BY-SA 3.0

308
zdan

Hier ist ein Flussdiagramm, das von David Moores Version (siehe oben) inspiriert wurde, die ich erstellt habe und die (meistens) auf dem neuesten Stand ist (C++ 11). Dies ist nur meine persönliche Meinung, es ist nicht unbestreitbar, aber ich dachte, es könnte für diese Diskussion wertvoll sein:

enter image description here

172
Mikael Persson

Einfache Antwort: Verwenden Sie std::vector für alles, es sei denn, Sie haben einen Grund, etwas anderes zu tun.

Wenn Sie einen Fall finden, in dem Sie denken: "Gee, std::vector funktioniert hier nicht gut wegen X", gehen Sie auf der Grundlage von X vor.

37
David Thornley

Schauen Sie sich Effective STL von Scott Meyers an. Es ist gut zu erklären, wie man die STL benutzt.

Wenn Sie eine bestimmte/unbestimmte Anzahl von Objekten speichern möchten und Sie niemals Objekte löschen möchten, ist ein Vektor das Richtige für Sie. Es ist der Standardersatz für ein C-Array. Es funktioniert wie ein Array, läuft aber nicht über. Sie können die Größe auch vorher mit reserve () einstellen.

Wenn Sie eine unbestimmte Anzahl von Objekten speichern möchten, Sie sie jedoch hinzufügen und löschen, möchten Sie wahrscheinlich eine Liste ... weil Sie ein Element löschen können, ohne die folgenden Elemente zu verschieben - im Gegensatz zum Vektor. Es erfordert jedoch mehr Speicher als ein Vektor, und Sie können nicht sequentiell auf ein Element zugreifen.

Wenn Sie eine Reihe von Elementen nehmen und nur die eindeutigen Werte dieser Elemente finden möchten, können Sie sie alle in einem Satz lesen, und Sie werden auch für Sie sortiert. 

Wenn Sie viele Schlüssel-Wert-Paare haben und diese nach Schlüssel sortieren möchten, ist eine Map nützlich ... aber sie enthält nur einen Wert pro Schlüssel. Wenn Sie mehr als einen Wert pro Schlüssel benötigen, können Sie einen Vektor/eine Liste als Wert in der Karte verwenden oder eine Multimap verwenden. 

Es ist nicht in der STL enthalten, aber es ist im TR1-Update der STL enthalten: Wenn Sie viele Schlüssel-Wert-Paare haben, werden Sie nach Schlüssel suchen und sich nicht um ihre Reihenfolge kümmern Ich möchte einen Hash verwenden - das ist tr1 :: unordered_map. Ich habe es mit Visual C++ 7.1 verwendet, wo es stdext :: hash_map hieß. Es findet eine Suche von O(1) statt einer Suche von O (log n) nach Karte statt.

10
Mark Krenitsky

Ich habe das Flussdiagramm mit drei Eigenschaften überarbeitet:

  1. Ich denke, STL-Container sind in 2 Hauptklassen unterteilt. Die Basiscontainer und diese nutzen die Basiscontainer zum Implementieren einer Richtlinie.
  2. Zunächst sollte das Flussdiagramm den Entscheidungsprozess auf die Hauptsituationen unterteilen, über die wir entscheiden sollten, und dann auf jeden Fall eingehen.
  3. Einige erweiterte Behälter haben die Möglichkeit, einen anderen Basisbehälter als Innenbehälter zu wählen. Das Flussdiagramm sollte die Situationen berücksichtigen, in denen jeder der Basiscontainer verwendet werden kann.

Das Flussdiagramm:  enter image description here

Weitere Informationen in diesem Link .

7
Ebrahim

Ein wichtiger Punkt, der bisher nur kurz erwähnt wurde, besteht darin, dass Sie, wenn Sie zusammenhängenden Speicher benötigen (wie es ein C-Array gibt), nur vector, array oder string verwenden können.

Verwenden Sie array, wenn die Größe zur Kompilierzeit bekannt ist.

Verwenden Sie string, wenn Sie nur mit Zeichentypen arbeiten müssen und eine Zeichenfolge benötigen, nicht nur einen allgemeinen Container.

Verwenden Sie in allen anderen Fällen vector (vector sollte in den meisten Fällen die Standardeinstellung für den Container sein).

Bei allen drei Elementen können Sie mit der Memberfunktion data() einen Zeiger auf das erste Element des Containers ermitteln.

4
Jonathan Wakely

Es hängt alles davon ab, was Sie speichern möchten und was Sie mit dem Container tun möchten. Hier einige (sehr unvollständige) Beispiele für die Containerklassen, die ich am häufigsten benutze:

vector: Kompaktes Layout mit wenig oder keinem Speicheraufwand pro enthaltenem Objekt. Effizient um zu iterieren. Das Anhängen, Einfügen und Löschen kann insbesondere für komplexe Objekte teuer sein. Es ist billig, ein enthaltenes Objekt anhand des Index zu finden, z. myVector [10]. Verwenden Sie die Stelle, an der Sie in C ein Array verwendet hätten. Gut, wenn Sie viele einfache Objekte haben (z. B. int). Vergessen Sie nicht, reserve() zu verwenden, bevor Sie dem Container viele Objekte hinzufügen.

list: Kleiner Speicheraufwand pro enthaltenem Objekt. Effizient um zu iterieren. Anhängen, Einfügen und Löschen sind billig. Verwenden Sie die Stelle, an der Sie in C eine verknüpfte Liste verwendet hätten.

set (und multiset): Bedeutender Speicheraufwand für jedes enthaltene Objekt. Verwenden Sie die Stelle, an der Sie schnell feststellen müssen, ob der Container ein bestimmtes Objekt enthält, oder fügen Sie Container effizient zusammen.

map (und multimap): Bedeutender Speicheraufwand für jedes enthaltene Objekt. Verwenden Sie die Stelle, an der Sie Schlüssel-Wert-Paare speichern möchten, und suchen Sie die Werte schnell nach Schlüssel.

Das von zdan vorgeschlagene Flussdiagramm auf dem Spickzettel bietet eine umfassendere Anleitung.

4
Bids

Eine Lektion, die ich gelernt habe, ist: Versuchen Sie, es in eine Klasse einzuwickeln, da das Wechseln des Behältertyps an einem schönen Tag zu großen Überraschungen führen kann. 

class CollectionOfFoo {
    Collection<Foo*> foos;
    .. delegate methods specifically 
}

Es kostet im Vorfeld nicht viel und spart Zeit beim Debuggen, wenn Sie den Vorgang unterbrechen möchten, wenn jemand die Operation x an dieser Struktur durchführt.

Zur Auswahl der perfekten Datenstruktur für einen Job:

Jede Datenstruktur bietet einige Operationen, deren zeitliche Komplexität variieren kann:

O (1), O (IgN), O (N) usw.

Sie müssen im Grunde eine bestmögliche Schätzung machen, welche Operationen am meisten ausgeführt werden, und eine Datenstruktur verwenden, die diese Operation als O (1) hat.

Einfach ist es nicht (-:

2
vrdhn

Ich erweiterte Mikael Perssons fantastisches Flussdiagramm. Ich habe einige Containerkategorien, den Array-Container und einige Notizen hinzugefügt. Wenn Sie eine eigene Kopie wünschen, ist hier die Google-Zeichnung. Danke, Mikael, dass du die Grundlagen geschaffen hast! C++ Container Picker

1
John DiFini

Ich habe dies in einer anderen Frage beantwortet, die als Dup dieser Frage gekennzeichnet ist. Ich finde es aber schön, auf einige gute Artikel bezüglich der Entscheidung für einen Standardcontainer Bezug zu nehmen.

Wie @David Thornley antwortete, ist std :: vector der richtige Weg, wenn es keine anderen besonderen Bedürfnisse gibt. Dies ist der Rat, den der Schöpfer von C++, Bjarne Stroustrup, in einem 2014 veröffentlichten Blog gegeben hat.

Hier ist der Link zum Artikel https://isocpp.org/blog/2014/06/stroustrup-lists

und zitieren von diesem,

Ja, meine Empfehlung ist, standardmäßig std :: vector zu verwenden. 

In den Kommentaren bietet der Benutzer @NathanOliver einen weiteren guten Blog mit konkreteren Maßen. https://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html

0
CS Pei