42 Stimmen

Klassenmitglieder und explizite Stapel-/Heap-Allokation

Angenommen, wir haben 4 Klassen wie folgt:

class A
{
    public:           
        A(void) : m_B()
        {
        }
    private:
        B m_B;
}

class B
{
    public:            
        B(void)
        {
           m_i = 1;
        }
    private:
        int m_i;
}

class C
{
    public:           
        C(void) 
        {
            m_D = new D();
        }
        ~C(void) 
        {
            delete m_D;
        }
    private:
        D *m_D;
}

class D
{
    public:           
        D(void)
        {
           m_i = 1;
        }
    private:
        int m_i;
}

Angenommen es gibt 4 Fälle:

Fall 1: A extern auf dem Stack allokiert, B intern auf dem Stack allokiert

A myA1;

Fall 2: A extern auf dem Heap allokiert, B intern auf dem Stack allokiert

A *myA2 = new A();

Fall 3: C extern auf dem Stack allokiert, D intern auf dem Heap allokiert

C myC1;

Fall 4: C extern auf dem Heap allokiert, D intern auf dem Heap allokiert

C *myC2 = new C();

Was passiert in jedem dieser Fälle? Zum Beispiel, im Fall 2, verstehe ich, dass der Zeiger myA2 auf dem Stack allokiert ist, das A-Objekt existiert im Heap, aber was ist mit dem Attribut m_B? Ich nehme an, dass auch Speicherplatz im Heap dafür allokiert wird, da es keinen Sinn hätte, dass ein Objekt im Heap existiert und dann sein Attribut außerhalb des Geltungsbereichs liegt. Wenn das stimmt, bedeutet das dann, dass die externe Heap-Allokation die interne Stack-Allokation überschreibt?

Was ist mit Fall 3, myC1 wird auf dem Stack allokiert, jedoch wird m_D auf dem Heap allokiert. Was passiert hier? Sind die beiden Teile über den Speicher verteilt? Wenn ich 'delete m_D' aus dem Destruktor entfernen würde und myC1 außerhalb des Geltungsbereichs wäre, gäbe es dann ein Memory Leak für den im Heap allokierten Speicher für m_D?

Wenn es Tutorials/Artikel gibt, die dies ausführlich behandeln, würde ich mich über einen Link freuen.

65voto

Mesop Punkte 5037

Ich glaube, du verwechselst "Stack/Heap-Allokation" mit "Automatische Variable".

Automatische Variablen werden automatisch zerstört, wenn sie den Kontext verlassen.

Stack-Allokation bedeutet, dass der Speicher auf dem Ausführungsstapel allokiert wird. Und Variablen, die auf dem Stapel allokiert sind, sind automatische Variablen.

Außerdem sind Member automatische Variablen, deren Destruktoren aufgerufen werden, wenn ihr Besitzer zerstört wird. Im Falle von Zeigern werden sie zerstört, aber nicht das zugrunde liegende Objekt, du musst explizit delete aufrufen. Um sicherzustellen, dass das zugrunde liegende Objekt zerstört wird, musst du kluge oder eindeutige Zeiger verwenden.

Anders ausgedrückt: Variablen/Member, bei denen du delete aufrufen musst, sind keine automatischen Variablen.

Zuletzt werden Member einer Klasse im selben Speichersegment wie ihr Besitzer allokiert.

In deinem Code:

  • A.m_B ist eine automatische Variable. Wenn A auf dem Stack ist, ist es auch B und wenn A im Heap ist, dann auch B.
  • B.m_i und D.m_i sind automatische Variablen und werden im selben Speichersegment wie ihre Besitzer allokiert
  • Der Zeiger C.m_D ist eine automatische Variable, aber das darauf zeigende Objekt vom Typ D ist es nicht; du musst delete für den Zeiger aufrufen, um das zugrunde liegende Objekt zu löschen. Also wird der Zeiger C.m_D im selben Speichersegment allokiert, aber nicht das zugrunde liegende Objekt. Es wird klar durch new allokiert und wird im Heap sein.

Also:

  • Fall 1: Alles ist auf dem Stack und automatisch (d.h.: wird automatisch zerstört).
  • Fall 2: myA2 ist im Heap und nicht automatisch (du musst delete myA2 aufrufen). Ihr Mitglied m_B2 ist eine automatische Variable, die zerstört wird, wenn myA2 zerstört wird. Da myA2 im Heap ist, ist auch m_B, wie jedes Mitglied einer Klasse, im selben Speicherbereich wie der Heap.
  • Fall 3: myC1 ist auf dem Stack und ist eine automatische Variable, Der Zeiger auf m_D ist auch auf dem Stack, aber nicht das durch m_D gezeigte Objekt, das durch new im Heap allokiert wurde.
  • Fall 4: Wie Fall 3, aber myC2 ist im Heap und nicht automatisch. Du musst also myC2 löschen (was auch m_D löschen wird).

9voto

juanchopanza Punkte 216358

Fall 1: alles auf dem "Stack" (automatischer Speicher). Ressourcen werden freigegeben, wenn Sie den Scope verlassen.

Fall 2: myA2 befindet sich im "Heap", ebenso wie sein m_B, und Sie müssen sich nur um das Freigeben der Ressourcen kümmern, die durch myA2 belegt sind. Sein m_B wird automatisch destruiert, wenn myA2 wird.

Fall 3: myC1 befindet sich auf dem Stack, sein m_D zeigt auf ein D im Heap, aber der Destruktor von C kümmert sich um das Löschen davon, so dass beim Verlassen des Gültigkeitsbereichs von myC1 alle dynamisch zugewiesenen Ressourcen freigegeben werden.

Fall 4: myC2 dynamisch zugewiesen, das muss gelöscht werden, um die belegten Ressourcen freizugeben. Das Löschen ruft seinen Konstruktor auf, der sich seinerseits um m_D kümmert, wie im Fall 3.

Ich bin mir nicht sicher über Artikel, ich bin sicher, dass es viele gibt. Aber ich empfehle, einige gute C++-Bücher zu lesen.

2voto

tonytony Punkte 1936

Ihr Objekt ist ein Stück organisierter Speicher. Ein Objekt weist seine Elemente nicht dem Speicher zu, sondern besteht nur aus diesen.

Fall 2: Das gesamte Objekt befindet sich im Heap, das bedeutet, dass alle seine Elemente im Heap liegen.

Fall 3: Das gesamte Objekt existiert auf dem Stack. Der Trick besteht darin, dass es kein D-Klasseninstanz ist, die Mitglied von myC1 ist, sondern ein Zeiger auf B, der physisches Mitglied von myC1 ist. Das Mitglied von myC1 befindet sich also auf dem Stack und zeigt auf eine D-Instanz, die sich im Heap befindet.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X