| Autor |
Beitrag |
Dornathal
      
Beiträge: 38
|
Verfasst: Mi 17.10.07 15:29
Hallo Leute.
Ist wahrscheinlich e ziemlich doofe frage: Aber ich würde gerne einmaal wissen, wie sich diese Anweisungen auf den Speicher auswirken.
Also ich habe eine Klasse programmiert, die ein paar functionen als Methoden hat. Dies soll ein Vektor auf 2D Ebene Darstellen.
Ich bin an dem Schulprojekt der voneinanderabprallenden Bällen beschäftigt.Deshalb möchte ich Vektoren verwenden um die neuen Richtungen der Bälle möglichst genau zu bestimmen.
Eine Funktion wäre das hier: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| function TVektor.AddiereVektor(Vektor1,Vektor2: TVektor):TVektor; var ResultVektor: TVektor; begin ResultVektor:= TVektor.init(0,0); ResultVektor.X:= Vektor1.X+Vektor2.X; ResultVektor.Y:= Vektor1.Y+Vektor2.Y; Result:= ResultVektor; end; |
Ich würde nun gerne wissen was mit dem Vektor geschieht den ich in dieser Funktion initialisiert habe (init ist der Constructor). Wird der automatisch wieder freigegebenanchdem dei Mathode beendet wurde, muss ich den selbst wieder freigeben.
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Mi 17.10.07 15:32
Hallo!
Da Du den Vektor ja als Ergebnis zurückgibst, wäre es nicht sinnvoll, diesen in der Funktion wieder freizugeben. Das machst Du außerhalb der Funktion, wenn Du ihn nicht mehr brauchst.
Grüße
Christian
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Dornathal 
      
Beiträge: 38
|
Verfasst: Mi 17.10.07 16:32
Ahh danke.
Also noch ne kurze Frage: Ich habe zwei TVektoren initialisiert:
Vektor1 und vektor2
Wenn ich nun diese Funktion ausführe:Vektor1.addierevektor(Vektor1,Vektor2);
Wie viel Speicherplatz hab ich nun verbraucht? 2 oder 3 vektoren.
Denn ich hatte ja schon zwei Vektoren hab dann noch einen initialisiert den aber auf einen anderen kopiert, ohne ihn vorher freizugeben.
|
|
Reinhard Kern
      
Beiträge: 591
Erhaltene Danke: 14
|
Verfasst: Mi 17.10.07 17:30
Christian S. hat folgendes geschrieben: | Hallo!
Da Du den Vektor ja als Ergebnis zurückgibst, wäre es nicht sinnvoll, diesen in der Funktion wieder freizugeben. Das machst Du außerhalb der Funktion, wenn Du ihn nicht mehr brauchst.
Grüße
Christian |
Hallo Christian,
ich bin mit deiner Antwort nicht einverstanden. Im vorliegenden Fall kann sein Konstrukt zwar funktionieren, wenn der Vektor auf dem Heap initialisiert wird, und er gibt die Adresse davon zurück. Aber es ist nun mal grundsätzlich eine Todsünde in allen Programmiersprachen, eine lokale Variable der Funktion als Ergebnis zurückzugeben, so was darf man sich nicht angewöhnen - und i.A. sind auch die Folgen nicht absehbar. Würde z.B. Delphi den Speicherplatz für den Vektor auf dem Stack reservieren, würde der Zeiger nach dem Rücksprung ins Datennirwana zeigen.
So weit darf man sich nicht auf spezielle Compilereigenheiten verlassen.
Gruss Reinhard
|
|
Dornathal 
      
Beiträge: 38
|
Verfasst: Mi 17.10.07 20:00
@Reinhard
Das Bedeutet dass ich das auf eine andere Weise machen soll. Aber wie? Ich würde gerne Vektor1 und Vektor2 nicht verändern. Die Veränderung von Vektor1 wirkt sich dann ja auf den Originalvektor aus.
Ich würde die Funktion nämlich gerne dafür benutzen einen Resultierenden vektor zu schaffen in dem zwei addierte vektoren enthalten sind, ohne die originalvektoren zu verändern. Andererseits möchte ich zu einem vektor einfach einen anderen hinzufügen. Dann überschreibe ich ja den originalvektor.
Sollte man dann zwei functionen erstellen?
Hmm immoment jedenfalls weis ich keine Lösung dafür, die einfach in den Code zu übertragen ist... bz ich weis gar keine Lösung.
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Mi 17.10.07 21:15
Hallo!
Reinhard Kern hat folgendes geschrieben: | | Im vorliegenden Fall kann sein Konstrukt zwar funktionieren, wenn der Vektor auf dem Heap initialisiert wird, und er gibt die Adresse davon zurück. Aber es ist nun mal grundsätzlich eine Todsünde in allen Programmiersprachen, eine lokale Variable der Funktion als Ergebnis zurückzugeben, so was darf man sich nicht angewöhnen - und i.A. sind auch die Folgen nicht absehbar. |
Im Allgemeinen ist für mich eher uninteressant, es interessierte mich mal, wie Delphi das macht (ich nutze selber kein Delphi mehr, weil ich nur noch in .NET entwickle) und jetzt wie es im Framework gehandhabt wird.
Aber IIRC geht es in Delphi so und ich muss mich als Programmierer darauf verlassen können, dass das auch in nächster Zeit so funktioniert. Es wäre absoluter Wahnsinn, wenn Codegear plötzlich das Verhalten des Compilers derart ändern würde, dass bestehender Code nicht mehr kompiliert bzw. zur Laufzeit Fehler erzeugt. Und auf der Basis kann ich auch keine Programme entwickeln.
Grüße
Christian
//Edit: "bzw. zur Laufzeit Fehler erzeugt" eingefügt
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Zuletzt bearbeitet von Christian S. am Do 18.10.07 09:18, insgesamt 1-mal bearbeitet
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Do 18.10.07 07:04
Bei deiner Fragestellung nach 'AddVector' fällt mir auf, das Du in der Methode ein Verhalten implementierst, das der Klasse zugehörig ist. Ich würde die Methode dann als Klassenmethode deklarieren, weil für die Addition zweier Vektoren keine Instanz der Klasse nötig ist.
Grundsätzlich halte ich das aber für keine gute Idee. Ich würde es so machen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| Procedure TVector.AddVector (aVector : TVector); Begin Self.X := Self.X + aVector.X; Self.Y := Self.Y + aVector.Y; End;
... Var V1,V2,V3 : TVector;
Begin V1 := TVector.Create (1,2); V2 := TVector.Create (3,4);
V3 := TVector.Create (V1); V3.Add (V2);
V3.Free; V2.Free; V1.Free; .... |
Mir sind Funktionen, die Speicher alloziieren, ein Dorn im Auge. Denn man sieht ja nicht 'auf den ersten Blick', das die Funktion 'AddVector' einen TVector instantiiert.
_________________ Na denn, dann. Bis dann, denn.
|
|
Stefan.Buchholtz
      
Beiträge: 612
WIN 2000, WIN XP, Mac OS X
D7 Enterprise, XCode, Eclipse, Ruby On Rails
|
Verfasst: Do 18.10.07 09:15
Reinhard Kern hat folgendes geschrieben: | [ich bin mit deiner Antwort nicht einverstanden. Im vorliegenden Fall kann sein Konstrukt zwar funktionieren, wenn der Vektor auf dem Heap initialisiert wird, und er gibt die Adresse davon zurück. Aber es ist nun mal grundsätzlich eine Todsünde in allen Programmiersprachen, eine lokale Variable der Funktion als Ergebnis zurückzugeben, so was darf man sich nicht angewöhnen - und i.A. sind auch die Folgen nicht absehbar. Würde z.B. Delphi den Speicherplatz für den Vektor auf dem Stack reservieren, würde der Zeiger nach dem Rücksprung ins Datennirwana zeigen.
So weit darf man sich nicht auf spezielle Compilereigenheiten verlassen.
|
Mit der Aussage bin ich mal so gar nicht einverstanden. Im Gegenteil ist es fast immer erlaubt und sinnvoll, eine lokale Variable als Funktionsergebnis zurückzugeben. Es ist nur nicht erlaubt, einen Zeiger auf eine lokale Variable zurückzugeben.
Und das in Delphi Objekte grundsätzlich auf dem Heap erzeugt werden, ist keine Compilereigenheit, sondern Teil der Sprachdefinition. Das ist nicht nur bei Delphi, sondern meines Wissens bei allen objektorientierten Pascal-Varianten so. Und die Rückgabe von Objekten als Funktionsergebnis ist eine in allen objektorientierten Programmiersprachen verwendete Technik und Teil von mehreren etablierten Design Patterns (Singleton, Factory, ...).
Stefan
_________________ Ein Computer ohne Windows ist wie eine Schokoladentorte ohne Senf.
|
|
Dornathal 
      
Beiträge: 38
|
Verfasst: Do 18.10.07 15:32
@ alzaimar: Also ich meinte ja ich würde die Funktion dann auf zwei Weisen versuchen zu verwenden. Einmal um einen neuen vektor zu erstellen der sozusagen der resultierendeVektor aus vektor1,Vektor2 ist.
Ich hab grade ebend noch einen Geistesblitz bekommen und zwar:
Wenn ich nen 3.Vektor bekommen möchte erstelle ich ihn einfach vor dem proceduraufruf.
Delphi-Quelltext 1: 2:
| erstellterVektor:= TVektor.init(0,0); Vektor1.AddiereVektor(Vektor1,Vektor2,erstellterVektor); |
Wenn nicht dann gebe ich den schon zu existierenden Vektor als 3. Parameter in die Procedur.
Delphi-Quelltext 1:
| Vektor1.AddiereVektor(Vektor1,Vektor2,Vektor1); |
Dann werden beide Aufrufsarten die ich haben wollte realisiert mit nur einer funktion. Sorry aber ich hatte gestern voll die Denkblockade.
Naja hier nochmal die abgeänderte AddiereVektor procedur << jetzt schon.
Delphi-Quelltext 1: 2: 3: 4: 5:
| procedure TVektor.AddiereVektor(Vektor1,Vektor2, ResultVektor: TVektor); begin ResultVektor.X:= Vektor1.X+Vektor2.X; ResultVektor.Y:= Vektor1.Y+Vektor2.Y; end; |
@Chris und Reinhard: Also ich finde das erstellen von Instanzen innerhalb in einer Funktion durchaus für angebracht. Man sollte aber immer in der Lage sein sie wieder zu entfernen bevor die Funktion beendet wird. Das Problem is meiner Meinung nach, dass die Instanzen vergessen werden freizugeben, da man es nicht sieht dass sie initialisiert werden. Nur nachdem der Prozessorspeicher , Arbeitsspeicher... kp ebend das ding was die Instanzen Speichert voll ist.
es ist sicherlich möglich aber in meinem Beispiel ebend besser zu lösen. Trotzdem danke an alle die geholfen haben.
|
|
|