Verwenden Vektoren bei der Zuweisung Speicher auf dem Heap oder dem Stapel?

151

Sind alle folgenden Aussagen wahr?

vector<Type> vect; //allocates vect on stack and each of the Type (using std::allocator) also will be on the stack

vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack

vector<Type*> vect; //vect will be on stack and Type* will be on heap. 

Wie wird der Speicher intern Typein einem vectoroder einem anderen STL-Container zugewiesen ?

Phelodas
quelle
1
Mögliches Duplikat der Klassenmitglieder und explizite Stapel- / Heap-Zuordnung
underscore_d

Antworten:

221
vector<Type> vect;

ordnet die vector, dh die Header-Informationen, dem Stapel zu, aber die Elemente im freien Speicher ("Heap").

vector<Type> *vect = new vector<Type>;

ordnet alles im freien Laden zu.

vector<Type*> vect;

ordnet das vectorauf dem Stapel und eine Reihe von Zeigern auf dem freien Speicher zu, aber wo dieser Punkt bestimmt wird, hängt davon ab, wie Sie sie verwenden (Sie könnten beispielsweise Element 0 auf den freien Speicher und Element 1 auf den Stapel zeigen).

Fred Foo
quelle
3
Aber ich habe ein Szenario, in dem ich einen Segmentierungsfehler erhalte, wenn Type bei der zweiten Deklaration groß wird. Ich nahm an, dass dies daran lag, dass Type auf dem Stapel zugewiesen wurde.
Phelodas
4
@Phelodas: Ohne Ihren Code zu sehen, ist dies unmöglich zu bewerten. Bitte öffnen Sie eine neue Frage.
Fred Foo
2
Ungefähr, vector<Type> vect;da sich die Elemente auf dem Heap befinden und sich die Header-Informationen auf dem Stapel befinden, was passiert mit den Elementspeichern, wenn die Header-Informationen wie die Funktionsrückgabe aus dem Speicher entfernt werden? Werden sie mit den Header-Informationen zurückgefordert oder nicht? Wenn dies nicht der Fall ist, führt dies zu einem Speicherverlust?
Flyrain
3
@flyrain: Vektoren räumen nach sich selbst auf. Lesen Sie mehr über RAII .
Fred Foo
1
@flyrain: das sollte funktionieren. Bitte posten Sie eine neue Frage mit weiteren Details. Wenn Sie den Link hier posten, kann ich ihn mir ansehen.
Fred Foo
24
vector<Type> vect; //allocates vect on stack and each of the Type (using std::allocator) also will be on the stack

Nein, vectbefindet sich auf dem Stapel, aber das Array, das intern zum Speichern der Elemente verwendet wird, befindet sich auf dem Heap. Die Elemente befinden sich in diesem Array.

vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack

Nein. Wie oben, außer dass die vectorKlasse ebenfalls auf dem Haufen liegt.

vector<Type*> vect; //vect will be on stack and Type* will be on heap. 

vectbefindet sich auf dem Stapel, seine Elemente (Zeiger auf Type) befinden sich auf dem Heap, und Sie können nicht sagen, auf welche Types die Zeiger zeigen. Könnte auf dem Stapel sein, könnte auf dem Heap sein, könnte in den globalen Daten sein, könnte nirgendwo sein (dh NULLZeiger).

Übrigens könnte die Implementierung tatsächlich einige Vektoren (typischerweise von geringer Größe) vollständig auf dem Stapel speichern. Nicht dass ich von einer solchen Implementierung wüsste, aber es kann.

jpalecek
quelle
23

Unter der Annahme einer Implementierung, die tatsächlich einen Stapel und einen Heap enthält (Standard-C ++ erfordert solche Dinge nicht), ist die einzig wahre Aussage die letzte.

vector<Type> vect;
//allocates vect on stack and each of the Type (using std::allocator) also will be on the stack

Dies gilt bis auf den letzten Teil ( Typewird nicht auf dem Stapel sein). Vorstellen:

  void foo(vector<Type>& vec) {
     // Can't be on stack - how would the stack "expand"
     // to make the extra space required between main and foo?
     vec.push_back(Type());
  }

  int main() {
    vector<Type> bar;
    foo(bar);
  }

Gleichfalls:

 vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack

Richtig mit Ausnahme des letzten Teils mit einem ähnlichen Gegenbeispiel:

  void foo(vector<Type> *vec) {
     // Can't be on stack - how would the stack "expand"
     // to make the extra space required between main and foo?
     vec->push_back(Type());
  }

  int main() {
    vector<Type> *bar = new vector<Type>;
    foo(bar);
  }

Zum:

vector<Type*> vect; //vect will be on stack and Type* will be on heap. 

Dies ist wahr, aber beachten Sie hier, dass sich die Type*Zeiger auf dem Heap befinden, aber die TypeInstanzen, auf die sie verweisen, müssen nicht sein:

  int main() {
    vector<Type*> bar;
    Type foo;
    bar.push_back(&foo);
  }
Flexo
quelle
In welchem ​​Kontext hätten Sie keinen Stapel? Ich verstehe, Sie sagen, der Standard verlangt es nicht, aber praktisch, wann wären Sie ohne Stapel?
Nerdtron
3
@Nerdtron - IIRC Auf einigen kleinen Mikrocontrollern haben Sie einen Aufrufstapel, der zum Zeitpunkt des letzten Aufrufs nichts anderes als den PC (Programmzähler) speichern kann und für einen RET bereit ist. Ihr Compiler kann sich daher dafür entscheiden, "automatischen Speicher" (für nicht rekursive Funktionen) an einem festen Ort zu platzieren, der wenig oder gar keinen Bezug zum Ausführungsfluss hat. Es könnte das gesamte Programm vernünftigerweise abflachen. Selbst für den rekursiven Fall könnten Sie eine "Stapel pro Funktion" -Richtlinie oder einen separaten Stapel für automatische Variablen und Rücksprungadressen haben, was den Ausdruck "der Stapel" etwas bedeutungslos macht.
Flexo
Sie könnten die Heap-basierte Zuordnung für alles verwenden und über einen "Bereinigungsstapel" verfügen, der den automatischen Speicher (und möglicherweise deleteauch) verwaltet.
Flexo
3

Nur diese Aussage ist wahr:

vector <Type*> vect; //vect will be on stack and Type* will be on heap.

Type* Zeiger werden auf dem Heap zugewiesen, da sich die Anzahl der Zeiger dynamisch ändern kann.

vect In diesem Fall wird der Stapel zugewiesen, da Sie ihn als lokale Stapelvariable definiert haben.

Alexei Khlebnikov
quelle
2
Typ * zeigt keine Heap-Zuordnung an, sondern lediglich einen Zeiger auf ein Type-Objekt. Der Vektor speichert jedoch den Zeiger auf dem Heap. int a = 5; int * ptr_to_a = & a; Vektor <int *> vec; vec.push_back (ptr_to_a); (siehe jpaleceks Antwort)
Matthew Russell
1

Der Vektor hat einen internen, allocatorder für die Zuweisung / Freigabe von Speichern von heapfür die zuständig ist vector element. Egal wie Sie einen Vektor erstellen, er elementwird immer auf dem Vektor zugewiesen heap. Die Metadaten des Vektors hängen davon ab, wie Sie ihn erstellen.

Bingo
quelle