new int[size] vs std::vector
Zuweisen dynamischer Speicher, ich habe mit Vektoren die ganze Zeit in C++.
Aber vor kurzem, während des Lesens einige source-code, fand ich die Verwendung von "new int[Größe]" und auf einige der Forschung, festgestellt, dass es auch reserviert dynamischen Speicher.
Kann jemand mir einen Rat geben, welche ist besser? Ich bin auf der Suche von einer algorithmischen und ICPC Sicht?
- Es ist anders, weil, wenn Sie die dynamische Zuweisung von arrays, sind Sie zuerst zu erklären, eine
int *
Zeiger und rufen dann später neue auf, dann die Zuordnung der Zeiger zu derint
Zeiger aus dem Aufrufnew
. Mit Vektoren, die Sie nicht haben, um sorgen über den Aufrufdelete[]
und Sie der Größe verändert werden kann mit Leichtigkeit. - mögliche Duplikate von die dynamische Zuweisung ein array von Objekten
- Verwenden Sie immer
vector
. Array-new
ist alle, aber völlig nutzlos in der modernen C++, und vermutlich existiert es nur als ein Versuch zu besänftigen Wiederherstellung von C-Programmierern. Die (Globale) Platzierung version von array-neu ist auch völlig unbrauchbar. - möglich, Duplikat der Verwendung von arrays und std::Vektoren in C++, was die performance-Lücke?
- Sie müssen wirklich, Lesen Sie diese Antwort - stackoverflow.com/questions/6500313/... es erklärt viele Aspekte
Du musst angemeldet sein, um einen Kommentar abzugeben.
Immer lieber den standard-Containern. Sie haben klar definierte Kopier-Semantik, sind exception-sicher und richtig befreien.
Wenn du manuell zuweisen, müssen Sie sicherstellen, dass der Freigabe-code wird ausgeführt, und als Mitglieder, Sie müssen schreiben, korrigieren, kopieren, Zuweisung und copy-Konstruktor, der das richtige tut, ohne zu lecken in Ausnahmefällen.
Handbuch:
Wenn wir wollen, dass unsere Variablen haben nur den Spielraum, den Sie wirklich brauchen, wird es stinkig:
Oder einfach nur:
Es ist ein horror zu implementieren, die für eine Klasse, die die copy-Semantik. Kopieren kann werfen, kann bei der Zuteilung berücksichtigt zu werfen, und wir wollen, transaktionssemantik, ideal. Ein Beispiel platzen würde diese Antwort tho.
Ok hier.
Kopierbar Klasse - Handbuch Ressourcenmanagement vs-Container
Wir haben diesen unschuldigen Blick Klasse. Wie es sich herausstellt, ist es ziemlich böse. Ich fühle mich daran erinnert, American McGee ' s Alice:
Lecks. Die meisten Anfänger C++ - Programmierer zu erkennen, es fehlt löscht. Hinzufügen:
Undefiniertes Verhalten. Fortgeschrittene C++ - Programmierer erkennen, dass die falschen delete-operator verwendet. Dieses Problem beheben:
Schlechtes design, Dichtheit und Doppel-löscht lauern dort, wenn die Klasse kopiert wird. Das kopieren selbst ist in Ordnung, der compiler sauber kopiert den Zeiger für uns. Aber der compiler nicht emittieren code zum erstellen von Kopien der arrays.
Etwas mehr erfahrener C++ - Programmierer erkennen, dass die Regel der Drei wurde nicht eingehalten, die besagt, dass, wenn Sie haben explizit geschrieben Destruktor, copy-Zuweisung oder Kopie-Konstruktor, werden Sie wahrscheinlich auch schreiben müssen, die anderen, oder Sie privat ohne Umsetzung:
Richtig. ... Vorausgesetzt, können Sie garantieren, nie aus der Erinnerung und, dass weder Bar, noch Zerlegen können, nicht auf das kopieren. Spaß beginnt im nächsten Abschnitt.
Das Wunderland zu schreiben, exception-sicheren code.
Bau
f_
ausfällt?Frobs
, die gebaut wurden, sind zerstört. Stellen Sie sich 20Frob
gebaut wurden, die 21 wird scheitern. Als, in LIFO-Reihenfolge, die ersten 20Frob
werden ordnungsgemäß vernichtet.Das ist es. Bedeutet: Sie haben 64 zombie
Bars
jetzt. DieFoos
Objekt selbst kommt nie zu Leben, der Destruktor wird daher nicht aufgerufen werden.Wie machen wir diese Ausnahme sicher?
Einen Konstruktor sollte immer erfolgreich komplett oder scheitern komplett. Es sollte nicht sein, die Hälfte live, Hälfte-Toten. Lösung:
Kopieren
Erinnern Sie sich an unsere Definitionen zum kopieren:
Bar
kopieren müssen schwere Ressourcen unter der Haube. Es kann scheitern, es wird.Dies bedeutet, dass unsere
Foo
ist nun inkonsistent und unberechenbar Zustand. Geben Sie transaktionssemantik, benötigen wir zum Aufbau des neuen Staates ganz oder gar nicht, und verwenden Sie dann Operationen, die nicht werfen Implantat, der neue Staat in unseremFoo
. Schließlich müssen wir bereinigen den Zwischenstand.Die Lösung ist die Verwendung der Kopier-und swap-idiom (http://gotw.ca/gotw/059.htm).
Erste, wir verfeinern unser copy-Konstruktor:
Dann definieren wir einen nicht-werfen-swap-Funktion
Nun können wir unsere neue exception-sichere copy-Konstruktor und der Ausnahme-safe-swap-Funktion schreiben, die eine exception-sichere copy-Zuweisung-operator:
Was ist passiert? Zuerst bauen wir neue Speicher und kopieren rhs' in es. Dies kann werfen, aber wenn es funktioniert, unser Staat wird nicht verändert und bleibt das Objekt gültig ist.
Dann tauschen wir unsere Eingeweide mit dem temporären Eingeweiden. Die temporären bekommt, was nicht mehr benötigt wird, und gibt das Zeug am Ende des Bereichs. Wir haben effektiv verwendet tmp wie eine Mülltonne, und richtig wählen, RAII wie die Müllabfuhr.
Möchten Sie vielleicht zu schauen, http://gotw.ca/gotw/059.htm oder Lesen
Exceptional C++
für weitere Informationen über diese Technik und über das schreiben von exception-sicheren code.Setzen Sie zusammen
Zusammenfassung von dem, was kann nicht werfen oder ist nicht erlaubt zu werfen:
Und hier ist endlich unsere sorgfältig gestaltete, exception-safe, korrigierte version von Foo:
Vergleichen, dass unsere anfängliche, unschuldige auf der Suche code ist böse bis auf die Knochen:
Du besser nicht noch mehr Variablen. Früher oder später werden Sie vergessen, hinzuzufügen richtigen code an einem bestimmten Ort, und Ihre ganze Klasse krank wird.
Oder machen Sie es nicht-kopierbar.
Für einige Klassen ist dies sinnvoll (streams, für eine Instanz; zu teilen streams, explizit mit std::shared_ptr), aber für viele ist es nicht.
Die wirkliche Lösung.
Diese Klasse hat sauber das kopieren der Semantik, ist exception-sicher (Sie erinnern sich: als Ausnahme sicher, bedeutet nicht, nicht zu werfen, sondern um keine Lecks und möglicherweise haben transaktionssemantik), und nicht Leck.
In fast jeder situation
std::vector
vorzuziehen ist. Es hat ein Destruktor den Speicher frei, während manuell verwalteten Speicher muss explizit gelöscht werden, sobald Sie fertig sind mit ihm. Es ist sehr einfach einzuführen, memory leaks, zum Beispiel, wenn etwas löst eine exception aus, bevor es gelöscht wird. Zum Beispiel:Ist es auch bequemer, wenn Sie brauchen, um die Größe oder kopieren Sie die array.
Ist der einzige Grund, lieber ein raw array ist, wenn Sie extreme Leistung oder Speicher-Beschränkungen.
vector
ist ein größeres Objekt über einen Zeiger (mit Größe und Kapazität, Informationen); und es wird manchmal Wert-Initialisierung seiner Objekte, während eine raw-array wird default-initialisiert Sie (die triviale Arten bedeutet, dass Sie Links uninitialised).In den seltenen Fällen, wenn diese Fragen wichtig sein könnten, sollten Sie erwägen
std::unique_ptr<int[]>
; es hat einen destructor, die verhindern Speicherlecks und hat keine Laufzeit-overhead im Vergleich zu einer raw-array.new
immer initialisiert das Objekt (aber für einige Arten, die möglicherweise ein no-op und das Ergebnis in ein Objekt mit unbestimmten Wert). Wenn Sie wollen nicht initialisierten Speicher können Sie die Zuweisung Funktion direkt, oder nur die reserve Platz in einem Vektor. Siehe meine Antwort auf eine andere Frage hier: stackoverflow.com/a/9708092/365496new
default-initialisiert. Stellt sich heraus, dass, wenn der Typ nicht eine Klasse oder ein array-Typ dann, dass bedeutet 'ist keine Initialisierung durchgeführt'. Also ich denke, es ist nur eine Zuweisung Funktion direkt, wenn Sie wollen nicht initialisierten Speicher für ein Klasse Typ.std::unique_ptr<int[]>
wissen Sie, warum das könnte wahr sein?Ich glaube nicht, dass es jemals einen Fall, wo
new int[size]
vorzuziehen ist. Sie werden manchmal sehen Sie es in der pre-standard-code, aber selbst dann glaube ich nicht, es wurde immer eine gute Lösung; in der pre-standard-Tage, wenn Sie nicht über ein äquivalent zustd::vector
in Ihrer tool-kit, Sie schrieb einer. Die einzigen Gründe, die Sie möglicherweise verwenden möchten, einnew int[size]
ist bei der Durchführung eines pre-standard-vector-Klasse. (Meine eigene getrennte Zuweisung und Initialisierung, wie die Container in der standard-Bibliothek, aber dies möglicherweise overkill für ein sehr einfaches Vektor-Klasse.)Obwohl beide Methoden reserviert dynamischen Speicher ist ein Objekt für die Handhabung von Daten beliebiger Länge (
std::vector<T>
), während die andere ist nur ein Zeiger auf eine fortlaufende Linie von Speicher-slots GrößeN
(int
s in diesem Fall).Unter anderem Unterschiede
Einen
std::vector<T>
wird automatisch die Größe der reservierte Speicher für Ihre Daten, wenn Sie versuchen, fügen Sie einen neuen Wert ein und es läuft aus dem Raum. Einint *
nicht.Einen
std::vector<T>
den Speicher zugewiesen, wenn der Vektor geht out of scope, einint *
nicht.Einen
int *
haben wenig bis gar keine overhead (im Vergleich zu den Vektor -), obwohlstd::vector<T>
ist nicht gerade eine neue Sache und ist in der Regel sehr optimiert. Dein Flaschenhals vermutlich woanders.Aber ein
std::vector<int>
wird immer verbraucht mehr Speicher als eineint *
, und einige Operationen wird immer ein wenig mehr Zeit.So, wenn es Speicher - /CPU-Beschränkungen und Sie wollen sich zu rasieren, die sich jeden einzelnen Zyklus, dass Sie möglich können.. verwenden Sie eine
int *
.Es gibt Situationen, in denen ist definitiv vorzuziehen, über die anderen!
Wenn Sie Sie brauchen, "roh"/"real" - Speicher und volle Kontrolle über ihn
operator new
ist Ihre beste Wette.Zum Beispiel, wenn Sie mit
- placement-new
.von raw/realer Speicher ich meine etwas, das nicht gemanagt wird und durch einen wrapper-container, wie
std::vector<T>
.Wenn Sie auf der Suche nach einem Behälter zu behandeln, willkürlich und nicht wollen, das Rad neu zu erfinden in Bezug auf Speicher-management;
std::vector<T>
(oder einer anderen geeigneten STL-container)::operator new(size_t)
Funktion, nicht dienew
Betreiber.new (something) int[size]
ist wahrscheinlich viel einfacher als das schreiben einer benutzerdefinierten Zuweisung fürstd::vector
.Intern der Vektor genau das gleiche tun auch wird es kümmern, den Speicher freizugeben. Es gibt also keinen Grund für die Verwendung des new-operators. std::vector ist ein Teil von c++, es ist standard, dass es geprüft wird und es sicher ist, nicht die raw-pointer, wenn Sie haben einige standard-Weg, um Ihre Arbeit zu erledigen.
Wenn Sie eine dynamisch dimensionierten Sequenz von Objekten, verwenden Sie einen Vektor. Bei Bedarf reservieren Sie raw-Speicher und verwalten Sie, dass der Speicher selbst reservieren von Speicher. Sie werden feststellen, dass manchmal Vektoren, die nützlich sind, und zu anderen Zeiten einen Flachbild-Speicher-Puffer ist besser.
Vektor ist besser, wenn
...
Manuelle Speicherverwaltung können leicht und oft führt zu Speicherverlusten, und-schlimmer noch Undefiniertes Verhalten.