4 Stimmen

c++ Referenz löschen

Ich bin immer noch lernen c + + und haben eine Frage, die offensichtlich sein kann, oder vielleicht weiß ich einfach nicht, was ich versuche zu tun. Ich habe Funktionen, die eine Matrix (eine Klasse, die ich geschrieben habe, die einen richtig geschriebenen Destruktor hat) nehmen und eine neue Matrix daraus erstellen und eine Referenz auf die neue zurückgeben. Ich muss möglicherweise Zehntausende von Malen auf diese Matrizen iterieren, also muss ich sicherstellen, dass ich keine Speicherlecks habe. Die Frage ist also, wie kann ich die Matrix, die ich nicht mehr benötige, richtig löschen, um Platz für die nächste zu schaffen? Hier ist der Code, den ich versuche, leckfrei zu machen:

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 gibt einen Verweis auf die Matrix wie in getX0() zurück:

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;
}

Der Aufruf von 'delete X0' schlägt also fehl, weil er einen Zeiger benötigt. delete &X0' sagt, dass der freizugebende Zeiger nicht zugewiesen wurde. Was ist der korrekte Weg, dies zu tun? Oder mache ich etwas völlig falsch? Bei zu großen Matrizen und zu vielen Iterationen wird mein groß Auf der Festplatte ist kein Platz mehr frei, was vermutlich bedeutet, dass ich jede Menge Speicherverluste habe.

6voto

Victor Nicollet Punkte 23939

Stroustrup R'lyeh Fhtagn .

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

Aber im Ernst: Versuchen Sie, die Matrizen auf dem Stapel (ohne new ) und sie so zurückgeben, wie sie sind. Sollte nicht zu viel Ärger verursachen, da sie ihre Daten dynamisch auf der Innenseite sowieso zuzuweisen scheinen, und ich vermute, NRVO gelten würde, um eine Kopie zu vermeiden (die zurückgegebene Matrix würde direkt in den entsprechenden Ort konstruiert werden. Die x0 y x1 Die Magie am Boden kann wie folgt umgesetzt werden:

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

Da eine Swap-Operation auf Ihrer dynamischen Matrix in Form eines Zeiger-Swaps (der sehr schnell ist) anstelle einer tatsächlichen Datenkopie implementiert werden kann, sollte dies extrem schnell sein.

2voto

Keith Randall Punkte 22725

Sie sollten Zeiger verwenden. Die Anweisung

DynamicMatrix<double> x0 = getX0(n);

Erzeugt 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;

1voto

Diego Sevilla Punkte 27639

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

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

Das würde mehr Sinn machen, da Sie einen neuen Zeiger zurückgeben. Dann müssen Sie ihn löschen, wie Sie einige Zeilen weiter unten zeigen.

Beachten Sie jedoch, dass Sie sich eine Menge Ärger ersparen können, wenn Sie boost::shared_ptr :

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.

0voto

Sonny Saluja Punkte 7043

Ihr Fehler ist hier:

DynamicMatrix<double> x0 = getX0(n);

Sie müssen nicht unbedingt Zeiger verwenden. Sie können auch einen Verweis auf das neu erstellte Objekt zurückgeben. Um den Speicher zu löschen, brauchen Sie nur die Adresse des Verweises zu nehmen; wenn Sie die Adresse eines Verweises nehmen, erhalten Sie die Adresse des Verweises; Sie sollten in der Lage sein,

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

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

0voto

Karl Knechtel Punkte 55450

Die Regeln für DynamicMatrix<double> sind im Wesentlichen dieselben wie für int .

Wenn die Variable auf dem Stack als "auto"-Variable alloziert wurde, dann ist der richtige Weg, sie zu bereinigen, nichts zu tun - sie einfach aus dem Anwendungsbereich fallen zu lassen. Sie sollten Ihren Code so weit wie möglich so gestalten, dass dies der Fall ist.

Wurde es mit "neu" zugewiesen, bereinigen Sie es mit "löschen".

Bitte ordnen Sie niemals etwas dynamisch zu und geben Sie es dann per Referenz zurück. Geben Sie den Zeiger zurück. Genau genommen, tun Sie das auch nicht. Verwenden Sie eine intelligente Zeigerklasse. Bitte.

Bitte weisen Sie keine Dinge dynamisch zu, wenn Sie es nicht müssen. Erstellen Sie einfach einen lokalen Wert und geben Sie ihn zurück - nach Wert (auf diese Weise kann man mit der Tatsache umgehen, dass man keinen Verweis auf eine nicht-statische lokale Variable zurückgeben kann). Sie würden niemals, niemals, niemals pensez à über das Schreiben von Code wie dem folgenden, richtig?

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

Nochmals: Die Regeln für DynamicMatrix<double> sind im Wesentlichen dieselben wie für int . Deshalb implementiert man Kopierkonstruktoren, Zuweisungsoperatoren und Destruktoren: damit dies tatsächlich so funktioniert, wie man es vernünftigerweise erwarten würde.

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