2010-12-12 7 views
4

Ich lerne immer noch C++ und habe eine Frage, die vielleicht offensichtlich ist, oder vielleicht weiß ich einfach nicht, was ich versuche zu tun. Ich habe Funktionen, die eine Matrix nehmen (eine Klasse, die ich geschrieben habe, die einen richtig geschriebenen Destruktor hat) und daraus eine neue Matrix erstellen, die einen Verweis auf die neue zurückgibt. Ich muss möglicherweise Zehntausende Male auf diesen Matrizen iterieren, also muss ich sicherstellen, dass ich keine Speicherlecks habe. Die Frage ist also, wie lösche ich die Matrix, die ich nicht mehr benötige, um Platz für die nächste zu schaffen? Hier ist der Code Ich versuche, leckagefrei zu bekommen:C++ Referenz löschen

DynamicMatrix<double> x0 = getX0(n); 

DynamicMatrix<double>exactU = getExactU(n); 

DynamicMatrix<double> b = getB(n) * w; 

DynamicMatrix<double> x1 = getX1(x0, b, w, n); 

while(!isConverged(exactU,x1,e)){ 
    delete x0; //<<<<< This doesn't work. Nor does delete &x0. 
    x0 = x1; 
    x1 = getX1(x0, b, w, n); 
} 

Jede der getX() Methoden erzeugt einen Zeiger auf eine Matrix, und liefert eine Referenz auf die Matrix, wie in getX0():

DynamicMatrix<double> &getX0(int n){ 
    DynamicMatrix<double>* mat1 = new DynamicMatrix<double>(n * n,1); 
    for (int i = 1 ; i <= n; i++){ 
     for (int j = 1; j <= n; j++){ 
      mat1->set((i-1)*n +j, 1, 0); 
     } 
    } 
    return *mat1; 
} 

Also dann, 'löschen X0' Fehler aufrufen, weil es einen Zeiger benötigt. 'delete & X0' gibt an, dass der freigegebene Zeiger nicht zugewiesen wurde. Was ist der richtige Weg, dies zu tun? Oder mache ich etwas völlig falsches? Mit Matrizen zu groß und mit zu vielen Iterationen, meine große Festplatte hat keinen Platz mehr, was ich nur annehmen kann bedeutet, ich habe Speicherlecks in Hülle und Fülle.

+0

Wenn auf Ihrer Festplatte kein Speicher mehr verfügbar ist, bedeutet dies, dass Ihre Auslagerungsdatei so konfiguriert ist, dass sie zu groß wird. –

Antwort

6

Stroustrup R'lyeh Fhtagn nennen können.

Schreiben MyType myVar = MyFunction() erstellt ein neues Objekt mit einem Konstruktor, der den Rückgabetyp myFunction als Argument akzeptiert. Was auch immer von myFunction zurückgegeben wurde, wird dann verworfen - in Ihrem Beispiel gibt getX0 einen Verweis auf ein Objekt zurück, das dynamisch zugewiesen wurde und deshalb durchgesickert ist.

Im Ernst, wenn auch - versuchen, die Matrizen auf dem Stapel (ohne new) zu schaffen und Rückkehr sie, wie sie ist.Sollte nicht zu viel Mühe verursachen, da sie scheinen, ihre Daten sowieso innen dynamisch zuzuordnen, und ich vermute, NRVO würde gelten, um zu vermeiden, eine Kopie zu machen (die zurückgegebene Matrix würde direkt an der passenden Stelle konstruiert werden. Die x0 und x1 Magie am Boden kann wie folgt realisiert werden:

x0.swap(x1); 
DynamicMatrix<double> temp = getX1(x0, b, w, n); 
x1.swap(temp); 

da ein Swap-Operation kann auf dynamische Matrix in Form eines Zeigers Swap umgesetzt werden (was sehr schnell ist) anstelle eines tatsächlichen Daten zu kopieren, sollte diese extrem sein schnell

+0

+1 für Lovecraft. – Kos

+1

Implementierung von Swap für eine Matrix-Klasse ist definitiv eine gute Idee. Aber die letzten beiden Zeilen könnten als 'getX1 (x0, b, w, n) .swap (x1);' geschrieben werden, was der übliche Stil ist, um den Inhalt einer lokalen Variablen mit der Rückkehr von einer Funktion zu vertauschen. –

+0

Meine Matrix-Klasse speichert die Daten dynamisch auf dem Heap. Muss ich die Swap-Funktion außer Kraft setzen, oder sollte es so funktionieren, wie Sie es beschreiben, ohne dass ich meine eigenen schreiben muss? – jakev

1

wenn getX() einen Zeiger zurückgibt, sollten Sie als die erste Zeile schreiben:

DynamicMatrix<double>* x0 = getX0(n); 

, dass mehr Sinn machen würde, wie Sie einen neuen Zeiger zurück. Dann müssen Sie es löschen, während Sie unten einige Zeilen anzeigen.

ist jedoch zu beachten, dass Sie eine Menge Probleme sparen boost::shared_ptr mit:

typedef boost::shared_ptr<DynamicMatrix<double> > dyn_matrix_ptr; 

dyn_matrix_ptr x0 (getX0(n)); 
// use x0 as a normal pointer 
... 
// You don't have to manually delete it, it will be deleted automatically. 
2

sollten Sie Zeiger verwenden. Die Aussage

DynamicMatrix<double> x0 = getX0(n); 

Erstellt eine Kopie einer Matrix. Sie wollen

DynamicMatrix<double> *getX0(int n){ 
    DynamicMatrix<double>* mat1 = new DynamicMatrix<double>(n * n,1); 
    ... 
    return mat1; 
} 

Dann

DynamicMatrix<double> *x0 = getX0(n); 
... 
delete x0; 
+0

ok, aber wie mache ich nun x0 = x1, so dass jeder auf eine separate Kopie zeigt? – jakev

+0

@JakeVA: 'lösche x0; x0 = new DynamicMatrix (x1); ' –

+0

@JakeVA: Aber Sie wollen keine Kopie, Sie wollen Besitz übergeben. –

0

Ihr Fehler ist hier:

DynamicMatrix<double> x0 = getX0(n); 

Sie nicht unbedingt Zeiger verwenden. Sie können einen Verweis auf das neue Objekt zurückgeben. Um den Speicher zu löschen, nehmen Sie einfach die Adresse der Referenz. Wenn Sie die Adresse einer Referenz verwenden, erhalten Sie die Adresse des Referenten. Sie sollten

// receive newed memory in a reference 
DynamicMatrix<double>& x0 = getX0(n); 

// &x0 should give you the address of the allocated memory. 
delete &x0; 
0

Die Regeln für DynamicMatrix<double> sind grundsätzlich die gleichen wie für int.

Wenn es auf dem Stapel als 'Auto'-Variable zugewiesen wurde, dann ist die richtige Weise, es zu bereinigen, nichts zu tun - lass es einfach außerhalb des Bereichs fallen. Sie möchten Ihren Code so weit wie möglich anordnen, so dass dies der Fall ist.

Wenn es mit 'neu' zugewiesen wurde, bereinigen Sie es mit 'löschen'.

Bitte nicht immer etwas dynamisch zuweisen und dann per Referenz zurückgeben. Gib den Zeiger zurück. Mach das auch nicht. Verwenden Sie eine intelligente Zeigerklasse. Bitte.

Bitte ordnen Sie Dinge nicht dynamisch zu, wenn Sie nicht benötigen. Machen Sie einfach einen lokalen Wert und geben Sie ihn zurück - durch den Wert (so behandeln Sie die Tatsache, dass Sie keine Referenz auf ein nicht statisches Local zurückgeben können). Du würdest nie, nie, jemals denken über das Schreiben von Code wie folgt, nicht wahr?

int& give_me_a_value() { 
    int* result = new int(rand()); 
    return *result; 
} 

wieder: die Regeln für DynamicMatrix<double> sind grundsätzlich die gleichen wie sie für int sind. Deshalb implementieren Sie Kopierkonstruktoren, Zuweisungsoperatoren und Destruktoren: Damit funktioniert das tatsächlich so, wie Sie es erwarten.

+0

Das Beispiel, das Sie gaben. Ich versuche immer noch, den Unterschied zwischen Referenzen und Zeigern zu unterscheiden und zwischen ihnen zu konvertieren. so ehrlich gesagt, ja ich könnte Code so schreiben. Das habe ich mit meinen Matrix-Klassen gemacht, und ich dachte, es wäre richtig. Ich denke, es ist für mich nicht intuitiv, wie die Rückgabe einer Referenz eine Kopie erstellt. – jakev

+0

Nun ... werfen Sie einen Blick auf diesen Code: 'int give_me_a_value() {int result = rand(); Ergebnis zurückgeben: 'Sieht das nicht viel mehr aus, naja, ** normal **? Ich hoffe wirklich, es tut wirklich, oder Sie haben von sehr, sehr seltsamen Referenzmaterialien gelernt.Die Rückgabe einer Referenz ** erstellt keine Kopie - das ist der Punkt. Rückgabe ** nach Wert ** tut. –

+0

Wenn eine Funktion einen Verweis auf etwas zurückgibt, sollte sie im Allgemeinen einen Verweis auf etwas zurückgeben **, das bereits existierte, als die Funktion aufgerufen wurde **. –