2016-05-21 24 views
0

Lange Rede kurzer Sinn, ich muss eine Hashtabelle mit linearem Hashing in C++ für die Universität kodieren. Die Hashtabelle funktioniert, aber die Ressourcen werden nicht freigegeben, was ein Problem darstellt, insbesondere, dass der Komponententest die Tabelle mit 100k + Werten testet und der zurückgelassene Müll riesig ist. Grundsätzlich, wenn ich den neuen Hash-Tabelle bin die Schaffung ich folgendes tue:Wie lösche ich ein dynamisches Array von Objekten mit Zeigern zu anderen Objekten (C++)

hashTable = new Bucket[this->tableSize]; 
     for (size_t i = 0; i < tableSize; i++) { 
      hashTable[i] = * new Bucket(); 
     } 

Jeder Eimer kann einen Zeiger auf einen anderen Überlauf Eimer enthalten, die so eingestellt werden kann oder nicht.

class Bucket { 
    private: 
     size_t bucketSize;                 
     size_t elementsInBucket;                
     E v[N]; // int v[N];                
     bool hasOverflow;                  
     Bucket * nextBucket = nullptr; 

Meine Frage ist, wie kann ich die ganze hashtable einschließlich der Eimer mit ihren potentiellen Überlauf Eimer löschen, wie die folgenden nur die Hälfte des belegten Speicher freigibt.

delete[] hashTable; 
hashTable = nullptr; 

Vielen Dank!

+0

Ein 'Bucket' ist im Wesentlichen nur ein Knoten einer verketteten Liste. Was ist der übliche Weg, um eine verknüpfte Liste zu löschen? – rwols

+0

Ich sehe keinen Destruktor für 'Bucket'. – Logicrat

+0

'virtuelle ~ Bucket() { löschen nextBucket; } 'Wenn ich den Destruktor code, bricht das Programm und ich bekomme eine EXC_BAD_ACCESS beim Expandieren des Arrays. – cookiemonster

Antwort

1

Wenn ich mich nicht irre, die folgende Codezeile ein Speicherverlust ist:

hashTable[i] = * new Bucket(); 

Was Sie hier tun, ist ein neues Bucket-Objekt auf dem Heap zuzuweisen und dann sofort nach Wert in Ihr Array zu kopieren. Der mit new erstellte Zeiger fällt nicht in den Geltungsbereich und der ursprüngliche Bucket auf dem Heap wird durchgesickert. Was Sie übrig haben, ist eine Kopie von dem, was Sie gerade im Heap zugeordnet und durchgesickert.

Stattdessen sollten Sie die Zeiger im Array als solche speichern:

hashTable = new *Bucket[this->tableSize]; 
for (size_t i = 0; i < tableSize; i++) { 
    hashTable[i] = new Bucket(); 
} 

und löschen Sie es als solche:

for (size_t i = 0; i < tableSize; i++) { 
    delete hashTable[i]; 
    hashTable[i] = nullptr; 
} 
delete[] hashTable; 
hashTable = nullptr; 

Sie sollten auch Ihre destructor löscht den Elementzeiger so stellen Sie sicher, dass Wenn Sie bei jedem Bucket-Zeiger delete aufrufen, wird der verschachtelte Speicher freigegeben:

~Bucket() { 
    delete nextBucket; 
    nextBucket = nullptr; 
} 

L ast, müssen Sie einen Code ändern, das dies tut:

hashTable[i].something 

dazu:

hashTable[i]->something 

Dies scheint mir der richtige Weg zu sein, dynamische Arrays zu handhaben.

+0

Danke! Ich werde es morgen ausprobieren, weil es hier zu spät ist: D – cookiemonster

3

Du sofort ein Bucket auf dieser Linie undicht:

hashTable[i] = * new Bucket(); 

Was das bedeutet ist:

  1. Vergeben Sie einen neuen Bucket und liefern einen Zeiger auf sie
  2. Dereferenziere der zurückgegebene Zeiger und übergeben Sie einen Verweis auf Ihre neue Bucket zu Bucket::operator=
  3. Kopieren Sie die leere Bucket in das bereits vorhandene Objekt hashTable[i]
  4. Verwerfen Sie den Zeiger auf die neu zugewiesene Bucket, wodurch es

hashTable ist ein Zeiger auf das erste Element aus einer Anordnung von tableSizeBucket s undicht. Diese Objekte sind bereits vorhanden, sodass Sie keine neuen Objekte in Ihrer Schleife zuweisen müssen.

Darüber hinaus haben Sie keinen Destruktor für Bucket angezeigt oder gezeigt, wie Sie Bucket::nextBucket zuweisen. Ich gehe davon aus jeder Bucket sollte seine nextBucket besitzen, so sollten Sie eine destructor haben, die so etwas wie

tut
Bucket::~Bucket() 
{ 
    delete nextBucket; 
} 
+0

Der Destruktor ist dem, den du geschrieben hast, ziemlich ähnlich. Zusätzlich weise ich nextBucket zu nullptr zu. Für die Zuweisung von nextBucket wird eine Methode add (const E & e) aufgerufen, um das Objekt dem Bucket hinzuzufügen. Wenn der aktuelle Bucket voll ist, wird ein neuer Bucket erstellt, und das Objekt wird in diesem Bucket hinzugefügt. Das Problem ist, dass wenn Sie einen solchen Destruktor verwenden, bekomme ich einen EXC_BAD + ACCESS – cookiemonster

+0

Etwas ist wahrscheinlich falsch in Ihrer 'add' Methode dann. Etwas, das am wahrscheinlichsten ein Double-Free oder ein-Usage-Free verursacht. –

+0

Der Fehler tritt auf, wenn überprüft wird, ob der aktuelle Bucket andere Überlaufbereiche aufweist. Aber danke! Ich werde es am Morgen nachsehen. – cookiemonster