Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Sender als const? (https://www.delphipraxis.net/41046-sender-als-const.html)

Pseudemys Nelsoni 25. Feb 2005 01:47


Sender als const?
 
Moin,

Standardmässig sind Sender ja ohne "const"(siehe TNotifyEvent), hätte das irgendein Nachteil in meinen eigenen methoden wenn ich selbiges dort benutze? also "const Sender: TObject" ? Bzw hätte dies einen Vorteil?

Luckie 25. Feb 2005 02:01

Re: Sender als const?
 
Guck doch in der Hilfe, was das const bei der Parameterübergabe bewirkt:
Zitat:

Using const allows the compiler to optimize code for structured- and string-type parameters. It also provides a safeguard against unintentionally passing a parameter by reference to another routine.
Bei Strings wird zum Beispiel nur der Referenzzähler erhöht, es wird also keine Kopie angelegt.

Ich zitiere mal aus Motzis String-Tutorial:
Zitat:

“normaler”- und const-Parameter
Deklaration und Aufruf einer Prozedur mit einem “normalen” Parameter:
Delphi-Quellcode:
procedure foo_normal(s: String);
var
s: String;
s := 'Test';
foo_normal(s);
Deklaration und Aufruf einer Prozedur mit einem const-Parameter:

Delphi-Quellcode:
procedure foo_const(const s: String);
var
s: String;
s := 'Test';
foo_const(s);
Auch diese beiden Methoden scheinen auf den ersten Blick identisch, wenn man sich den
erzeugten Assembler-Code für den Aufruf ansieht:
Assembler-Code des Aufrufs der Funktion mit „normalem“ Parameter:

Code:
mov eax, [ebp-$04]
call foo_normal
Assembler-Code des Aufrufs der Funktion mit const-Parameter:
mov eax, [ebp-$04]
call foo_const
Der eigentliche Unterschied wird erst in der aufgerufenen Funktion sichtbar. Während bei
einem const-Parameter dort nichts weiter wichtiges geschieht, findet man bei der Funktion mit
normalem Parameter folgende Code-Blöcke am Anfang:

Code:
push ebp
mov ebp, esp
push ecx
mov [ebp-$04],eax
mov eax,[ebp-$04]
call @LstrAddRef
xor eax,eax
push ebp
push $0046c81e
push dword ptr fs:[eax]
mov fs:[eax],esp
bzw. am Ende der Funktion:
xor eax,eax
pop edx
pop ecx
pop ecx
mov fs:[eax],edx
push $0046c825
lea eax,[ebp-$04]
call @LStrClr
ret
jmp @HandleFinally
jmp -$10
Durch diesen Code wird eine lokale Kopie des Strings angelegt, welche dann innerhalb der
Funktion benutzt wird, wodurch der übergebene String davor geschützt wird, verändert zu
werden. Außerdem wird noch extra ein SEH-Frame (SEH = Structured Exception Handling)
angelegt, damit die lokale Kopie des Strings auf jeden Fall am Ende wieder korrekt
freigegeben wird.

Dass das ganze dann natürlich wieder eine Menge Arbeit bedeutet, dürfte jedem einleuchten,
und dass sich diese Mehrarbeit eher schlecht auf das Laufzeitverhalten auswirkt, sollte auch
klar sein. Daher sollten Strings, wenn möglich, immer nur als const-Parameter bzw. wenn sie
von der aufgerufenen Funktion verändert werden sollen, als var-Parameter übergeben werden.

dizzy 25. Feb 2005 02:02

Re: Sender als const?
 
Nachteil: Du kannst nur noch lesend auf den Sender zugreifen
Vorteil: Du kannst nur noch lesend auf den Sender zugreifen
;)
Kommt halt drauf an was du vor hast, und ob dich der Compiler daran hindern soll am Sender zu fummeln. Ein var dürfte im Übrigen keinen Unterschied zur modifikatorlosen Deklaration machen, da eh nur eine Referenz übergeben wird, und bei Objekten, anders als bei Strings und Records, auch keine Duplikate im Hintergrund erzeugt werden (beim ersten schreibenden Zugriff innerhalb der betr. Methode).

Also macht es nur dann und dafür Sinn, wenn du sicher stellen willst, dass am Sender-Objekt nichts verändert werden kann.

jim_raynor 25. Feb 2005 06:25

Re: Sender als const?
 
Zitat:

Zitat von dizzy
Ein var dürfte im Übrigen keinen Unterschied zur modifikatorlosen Deklaration machen, da eh nur eine Referenz übergeben wird

Doch es macht einen Unterschied. Du kannst nämlich dann ein neues Objekt zurückgeben.

Beispiel:

Delphi-Quellcode:
procedure Test(sender: TObject);
begin
  Sender:=nil;
end;

procedure Test2(var sender: TObject);
begin
  Sender:=nil;
end;

var
  TestObject: TObject;
begin
  TestObject:=TObject.Create;

  Test(TestObject); // Nach dem Aufruf zeigt TestObject immer noch auf das erstellte Object

  Test2(TestObject); // Nach dem Aufruf zeigt TestObject auf nil.
end.
1. Probiere es doch einfach aus, ob du bei einem TNotfifyEvent ein const einbauen kannst. Ich glaube nämlich nicht, da sich die Aufrufe intern unterscheiden. Und bei Objekten macht es keinen Unterschied. Mit Const übergibt er die 4 Bytes Referenz auf die Variable ohne const übergibt er die 4 Bytes Referenz auf das Objekt selber. Du hast also nichts gewonnen.

Bernhard Geyer 25. Feb 2005 07:26

Re: Sender als const?
 
Zitat:

Zitat von dizzy
Nachteil: Du kannst nur noch lesend auf den Sender zugreifen

Ist nicht ganz genau. Du kannst den Referenzzeiger nicht verändern, sprich die Speicherstelle wo der Zeiger gespeichert ist. Das Objekt ansich kannst Du ganz normal über Property-Set-Methoden verändern.

Vorteil von const bei String/Widestring und array-Parametern ist, das das Programm kleiner und schneller wird. Bei Objekt-Referenzen ist der Vorteil dagegen "nur" das die Referenz nicht geändert werden kann - also Minimal.

Pseudemys Nelsoni 25. Feb 2005 13:18

Re: Sender als const?
 
Moin Leute,

ich weiss schon wo der Unterschied zwischen const/var/keiner angabe ist, meine Frage bezog sich mehr auf, ob es was nützt Pointer (also referenzen) mit const anzugeben ;)

Aber ich denke so wie sich das hier anhörte tut es das nicht :)


Was tut const eigentlich genau? Eine kopie der variable wird ja nicht angelegt, kann ich also davon ausgehen das es auch eine referenz ist die man nur nicht ändern kann?


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:48 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz