c++ programme - Wann ist es am besten, den Stack anstelle des Heaps zu verwenden und umgekehrt?




programming beispiel (8)

Verwenden Sie den Stapel, wenn Ihre Variable nicht verwendet wird, nachdem die aktuelle Funktion zurückgegeben wurde. Verwenden Sie den Heap, wenn die Daten in der Variablen über die Lebensdauer der aktuellen Funktion hinaus benötigt werden.

Wann ist es in C ++ am besten, den Stack zu verwenden? Wann ist es am besten, den Heap zu verwenden?


Die Frage ist schlecht formuliert.

Es gibt Situationen, in denen Sie den Stapel benötigen, andere, wo Sie den Heap benötigen, andere, wo Sie den statischen Speicher benötigen, andere, wo Sie die Speicherdaten benötigen, andere, wo Sie den kostenlosen Speicher benötigen.

Der Stapel ist schnell, da die Zuweisung nur ein "Inkrement" über den SP ist und die gesamte "Zuweisung" zum Aufrufzeitpunkt der Funktion erfolgt, in der Sie sich befinden. Heap (oder freier Speicher) Zuordnung / Freigabe ist zeitaufwendiger und fehleranfällig .


Als Faustregel verwenden Sie den Stapel wann immer Sie können. dh wenn die Variable außerhalb dieses Bereichs nie benötigt wird.

es ist schneller, verursacht weniger Fragmentierung und vermeidet die anderen Gemeinkosten, die mit dem Aufruf von malloc oder new verbunden sind. Aus dem Stapel gibt es einige Assembler-Operationen, malloc oder neu sind mehrere hundert Codezeilen in einer effizienten Implementierung.

es ist nie besser, den Haufen zu benutzen ... einfach unvermeidbar. :)


Verwenden Sie den Heap, um nur Speicherplatz für Objekte zur Laufzeit zuzuweisen. Wenn Sie die Größe zum Zeitpunkt der Kompilierung kennen, verwenden Sie den Stapel. Anstatt Heap-allokierte Objekte von einer Funktion zurückzugeben, übergeben Sie einen Puffer in die Funktion, in die geschrieben werden soll. Auf diese Weise kann der Puffer zugewiesen werden, wo die Funktion als ein Array oder eine andere stack-basierte Struktur aufgerufen wird.

Je weniger malloc () -Anweisungen Sie haben, desto weniger Möglichkeiten für Speicherlecks.


Eine Ausnahme von der oben genannten Regel, dass Sie den Stack generell für lokale Variablen verwenden sollten, die außerhalb des Funktionsumfangs nicht benötigt werden:

Rekursive Funktionen können den Stack-Space erschöpfen, wenn sie große lokale Variablen zuweisen oder wenn sie rekursiv mehrfach aufgerufen werden. Wenn Sie eine rekursive Funktion verwenden, die Speicher verwendet, ist es möglicherweise eine gute Idee, Heap-basierten Speicher anstelle von stapelbasiertem Speicher zu verwenden.


Als Faustregel gilt es, große Objekte auf dem Stapel zu vermeiden.

  • Das Erstellen eines Objekts auf dem Stapel befreit Sie von der Last, sich zu erinnern, das Objekt zu bereinigen (zu lesen). Wenn Sie jedoch zu viele Objekte auf dem Stapel erstellen, erhöht sich die Wahrscheinlichkeit eines Stapelüberlaufs.
  • Wenn Sie Heap für das Objekt verwenden, erhalten Sie so viel Speicher, wie das Betriebssystem bereitstellen kann. Das ist viel größer als der Stack, aber Sie müssen sicherstellen, dass Sie den Speicher freigeben, wenn Sie fertig sind. Wenn Sie zu häufig zu viele Objekte im Heap erstellen, wird der Speicher häufig fragmentiert, was sich wiederum auf die Leistung Ihrer Anwendung auswirkt.

Verwenden Sie den Stapel, wenn der verwendete Speicher streng auf den Bereich beschränkt ist, in dem Sie ihn erstellen. Dies ist nützlich, um Speicherlecks zu vermeiden, weil Sie genau wissen, wo Sie den Speicher verwenden möchten, und Sie wissen, wann Sie ihn nicht mehr benötigen, damit der Speicher für Sie aufgeräumt wird.

int main()
{ 
   if (...)
   {
      int i = 0;
   }
   // I know that i is no longer needed here, so declaring i in the above block 
   // limits the scope appropriately
}

Der Heap ist jedoch nützlich, wenn auf Ihren Speicher außerhalb des Erstellungsbereichs zugegriffen werden kann und Sie keine Stapelvariable kopieren möchten. Dies kann Ihnen explizite Kontrolle darüber geben, wie Speicher zugewiesen und freigegeben wird.

Object* CreateObject();

int main()
{
    Object* obj = CreateObject();
    // I can continue to manipulate object and I decide when I'm done with it

    // ..
    // I'm done
    delete obj;
    // .. keep going if you wish
    return 0;
}

Object* CreateObject()
{
   Object* returnValue = new Object();
   // ... do a bunch of stuff to returnValue
   return returnValue;
   // Note the object created via new here doesn't go away, its passed back using 
   // a pointer
}

Offensichtlich ist es ein häufiges Problem, dass Sie vergessen, Ihr Objekt zu löschen. Dies wird als Speicherleck bezeichnet. Diese Probleme treten häufiger auf, da Ihr Programm immer trivialer wird, wo "Ownership" (oder wer genau für das Löschen von Dingen verantwortlich ist) schwieriger zu definieren ist.

Gängige Lösungen in besser verwalteten Sprachen (C #, Java) sind die Implementierung der Garbage Collection, sodass Sie nicht über das Löschen von Dingen nachdenken müssen. Dies bedeutet jedoch, dass sich etwas im Hintergrund befindet, das aperiodisch ausgeführt wird, um Ihre Heap-Daten zu überprüfen. In einem nicht-trivialen Programm kann dies ziemlich ineffizient werden, wenn ein "Garbage Collection" -Thread erscheint und nach Daten sucht, die gelöscht werden sollen, während der Rest Ihres Programms blockiert wird.

In C ++ ist die gängigste und beste (meiner Meinung nach) Lösung, um mit Speicherlecks umzugehen, ein intelligenter Zeiger. Die gebräuchlichste davon ist boost::shared_ptr was ist ( Referenz gezählt )

Also um das obige Beispiel neu zu erstellen boost :: shared_ptr CreateObject ();

int main()
{
    boost::shared_ptr<Object> obj = CreateObject();
    // I can continue to manipulate object and I decide when I'm done with it

    // ..
    // I'm done, manually delete
    obj.reset(NULL);
    // .. keep going if you wish
    // here, if you forget to delete obj, the shared_ptr's destructor will note
    // that if no other shared_ptr's point to this memory 
    // it will automatically get deleted.
    return 0;
}

boost::shared_ptr<Object> CreateObject()
{
   boost::shared_ptr<Object> returnValue(new Object());
   // ... do a bunch of stuff to returnValue
   return returnValue;
   // Note the object created via new here doesn't go away, its passed back to 
   // the receiving shared_ptr, shared_ptr knows that another reference exists
   // to this memory, so it shouldn't delete the memory
}

Sortierte Arrays werden aufgrund von als Verzweigungsvorhersage genannten Phänomenen schneller als ein unsortiertes Array verarbeitet.

Der Zweigprädiktor ist ein digitaler Schaltkreis (in Computerarchitektur), der vorhersagt, in welche Richtung sich ein Zweig bewegen wird, wodurch der Fluss in der Anweisungspipeline verbessert wird. Die Schaltung / der Computer sagt den nächsten Schritt voraus und führt ihn aus.

Wenn Sie eine falsche Vorhersage treffen, kehren Sie zum vorherigen Schritt zurück und werden mit einer anderen Vorhersage ausgeführt. Wenn die Vorhersage korrekt ist, wird der Code mit dem nächsten Schritt fortgesetzt. Eine falsche Vorhersage führt dazu, dass derselbe Schritt wiederholt wird, bis eine korrekte Vorhersage erfolgt.

Die Antwort auf Ihre Frage ist sehr einfach.

In einem unsortierten Array trifft der Computer mehrere Vorhersagen, was zu einer erhöhten Fehlerwahrscheinlichkeit führt. In sortierter Weise macht der Computer weniger Vorhersagen, wodurch die Fehlerwahrscheinlichkeit verringert wird. Um mehr Voraussagen zu treffen, ist mehr Zeit erforderlich.

Sortiertes Array: Gerade Straße

____________________________________________________________________________________
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT

Unsortiertes Array: Kurvenreiche Straße

______   ________
|     |__|

Zweigvorhersagen: Erraten / Vorhersagen, welche Straße gerade ist, und dem folgen, ohne zu prüfen

___________________________________________ Straight road
 |_________________________________________|Longer road

Obwohl beide Straßen dasselbe Ziel erreichen, ist die gerade Straße kürzer und die andere ist länger. Wenn Sie dann versehentlich das andere wählen, gibt es kein Zurück mehr, und Sie werden etwas mehr Zeit verlieren, wenn Sie die längere Straße wählen. Dies ist vergleichbar mit dem, was auf dem Computer geschieht, und ich hoffe, dass Sie dadurch besser verstanden wurden.

Update: Nach dem, was @Simon_Weaver gesagt hat, möchte ich noch eine weitere Tatsache hinzufügen, dass ... "es nicht weniger Vorhersagen macht - es werden weniger falsche Vorhersagen gemacht. Es muss immer noch für jedes Mal durch die Schleife vorhergesagt werden."







c++