Frage

Cosider den folgenden Code:

class Foo
{
    Monster* monsters[6];

    Foo()
    {
        for (int i = 0; i < 6; i++)
        {
            monsters[i] = new Monster();
        }
    }

    virtual ~Foo();
}

Was ist der richtige destructor?

folgt aus:

Foo::~Foo()
{
    delete [] monsters;
}

oder folgt aus:

Foo::~Foo()
{
    for (int i = 0; i < 6; i++)
    {
        delete monsters[i];
    }
}

Im Moment habe ich den obersten Konstruktor und alles funktioniert okey, aber natürlich kann ich nicht sehen, ob es undichte werden passiert ...

Ich persönlich denke, die zweite Version ist viel logisch man bedenkt, was ich tue. Wie auch immer, was ist der „richtige“ Weg, dies zu tun?

War es hilfreich?

Lösung

delete[] monsters;

ist falsch, da monsters kein Zeiger auf einen dynamisch zugewiesenen Array ist, es is ein Array von Zeigern. Als Klassenmitglied wird sie automatisch zerstört werden, wenn die Klasseninstanz zerstört wird.

Ihre andere Implementierung ist die richtige, wie die Zeiger im Array tun Punkt dynamisch zugewiesen Monster Objekte.

Beachten Sie, dass mit Ihrer aktuellen Speicherzuweisungsstrategie möchten Sie wahrscheinlich Ihre eigene Kopie Konstruktor und Copy-Zuweisungsoperator erklären, so dass ein unbeabsichtigtes Kopieren nicht Ursache Doppel Löschungen. (Wenn Sie möchten, kopieren verhindern, dass Sie sie als privat erklären könnten und nicht tatsächlich umzusetzen.)

Andere Tipps

Für new Sie sollten delete verwenden. Für new[] Verwendung delete[]. Ihre zweite Variante ist korrekt.

Das zweite ist richtig unter den gegebenen Umständen (na ja, die am wenigsten falsch, sowieso).

Edit: „dest falsch“, wie sie in den ursprünglichen Code zeigt keinen guten Grund, mit new oder delete in erster Linie sein, so sollten Sie wahrscheinlich nur verwenden:

std::vector<Monster> monsters;

Das Ergebnis wird einfacher Code und sauberere Trennung von Verantwortlichkeiten.

Um die Answare Sehen wir uns auf den folgenden Code zu vereinfachen:

#include "stdafx.h"
#include <iostream>
using namespace std;

class A
{
private:
    int m_id;
    static int count;
public:
    A() {count++; m_id = count;}
    A(int id) { m_id = id; }
    ~A() {cout<< "Destructor A "   <<m_id<<endl; }
};

int A::count = 0;

void f1()
{   
    A* arr = new A[10];
    //delete operate only one constructor, and crash!
    delete arr;
    //delete[] arr;
}

int main()
{
    f1();
    system("PAUSE");
    return 0;
}

Die Ausgabe lautet: Destructor A 1 und dann ist es abstürzt. (Ausdruck: _BLOCK_TYPE_IS_VALID (phead- nBlockUse))

Wir müssen verwenden: delete [] arr; becuse es ist das gesamte Array löschen und nicht nur eine Zelle!

versuchen löschen verwenden [] arr; der Ausgang ist: Destructor A 10 Destructor A 9 Destructor A 8 Destructor A 7 Destructor A 6 Destructor A 5 Destructor A 4 Destructor A 3 Destructor A 2 Destructor A 1

Das gleiche Prinzip ist für eine Reihe von Zeigern:

void f2()
{
    A** arr = new A*[10];
    for(int i = 0; i < 10; i++)
    {
        arr[i] = new A(i);
    }
    for(int i = 0; i < 10; i++)
    {
        delete arr[i];//delete the A object allocations.
    }

    delete[] arr;//delete the array of pointers
}

, wenn wir stattdessen löschen arr von Lösch verwenden werden [] arr. es wird den ganzen Zeiger im Array => Speicherverlust von Zeigern Objekten nicht löschen!

delete[] monsters ist definitiv falsch. Mein Heap-Debugger zeigt die folgende Ausgabe:

allocated non-array memory at 0x3e38f0 (20 bytes)
allocated non-array memory at 0x3e3920 (20 bytes)
allocated non-array memory at 0x3e3950 (20 bytes)
allocated non-array memory at 0x3e3980 (20 bytes)
allocated non-array memory at 0x3e39b0 (20 bytes)
allocated non-array memory at 0x3e39e0 (20 bytes)
releasing     array memory at 0x22ff38

Wie Sie sehen können, Sie versuchen, mit der falschen Form löschen (nicht-Array vs. Array) zu lösen, und der Zeiger 0x22ff38 nie durch einen Aufruf an neue zurückgegeben. Die zweite Version zeigt die korrekte Ausgabe:

[allocations omitted for brevity]
releasing non-array memory at 0x3e38f0
releasing non-array memory at 0x3e3920
releasing non-array memory at 0x3e3950
releasing non-array memory at 0x3e3980
releasing non-array memory at 0x3e39b0
releasing non-array memory at 0x3e39e0

Wie dem auch sei, ziehe ich ein Design, bei dem manuell die destructor Umsetzung notwendig ist, nicht mit zu beginnen.

#include <array>
#include <memory>

class Foo
{
    std::array<std::shared_ptr<Monster>, 6> monsters;

    Foo()
    {
        for (int i = 0; i < 6; ++i)
        {
            monsters[i].reset(new Monster());
        }
    }

    virtual ~Foo()
    {
        // nothing to do manually
    }
};

Ihr zweites Beispiel ist korrekt; Sie nicht die monsters Array selbst, sondern nur die einzelnen Objekte, die Sie erstellt haben.

löschen müssen

Es wäre sinnvoll, wenn Ihr Code wie diese ist:

#include <iostream>

using namespace std;

class Monster
{
public:
        Monster() { cout << "Monster!" << endl; }
        virtual ~Monster() { cout << "Monster Died" << endl; }
};

int main(int argc, const char* argv[])
{
        Monster *mon = new Monster[6];

        delete [] mon;

        return 0;
}

löschen Sie jeden Zeiger einzeln, und Sie dann das gesamte Array löschen. Stellen Sie sicher, Sie haben eine richtige destructor für die Klassen definiert in dem Array gespeichert werden, sonst kann man nicht sicher sein, dass die Objekte richtig gereinigt werden. Seien Sie sicher, dass alle Ihre Destruktoren virtuell sind, so dass sie richtig verhalten, wenn sie mit Vererbung verwendet wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top