programming - c++ syntax




Wann ist es am besten, den Stack anstelle des Heaps zu verwenden und umgekehrt? (6)

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.

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


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. :)



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.


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.


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
}






c++