Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Code Optimisation: Benutzung von const in prozedur-Köpfen (https://www.delphipraxis.net/192983-code-optimisation-benutzung-von-const-prozedur-koepfen.html)

SneakyBagels 8. Jun 2017 10:17

Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Kürzlich habe ich irgendwo nebenbei gefragt, was const in Prozedurköpfen bringt.
Geantwortet wurde, dass der Code dadurch wohl optimierter sei.

Kann man also festhalten, dass wenn ich die Parameter nicht innerhalb der Prozedur veränderte, ich überall const verwenden kann?
Für Integer, Boolean, Strings und Typen?

TiGü 8. Jun 2017 10:28

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
https://www.delphitools.info/2010/07...nst-parameters

Namenloser 8. Jun 2017 10:30

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Ja, kannst du. Es schadet zumindest nicht. Bei Typen wie Integer, Char, Boolean etc. macht es aber in der Praxis keinen Unterschied, da eh immer der Wert kopiert wird. Bei größeren Typen wie Records kann const einiges ausmachen, weil dann nur noch ein Pointer übergeben wird, was schneller ist, als den ganzen Record zu kopieren. Und bei referenzgezählten Typen wie Strings spart man sich durch const ein addref und ein release.

bra 8. Jun 2017 10:41

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Ganz so trivial ist es aber leider auch nicht. Wenn du z.B. eine Klasse als const-Parameter übergibst, kannst du nur den Pointer nicht ändern, den Inhalt aber schon. Ich bin da auch schon drüber gestolpert, weil ich es von C++ anders kannte.

Auch führt folgendes zu m.E. seltsamen Ergebnissen:

Delphi-Quellcode:
var FString: String = 'Test';

procedure Change(const AString: String);
begin
  FString := 'Blubb';
  ShowMessage(AString);
end;

procedure CallMe;
begin
  Change(FString);
  Change(FString);
end;

Der schöne Günther 8. Jun 2017 11:16

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von bra (Beitrag 1373825)
Ich bin da auch schon drüber gestolpert, weil ich es von C++ anders kannte.

Oh ja, die const correctness ist auch mein Nummer 1-Feature das ich aus C++ vermisse

SneakyBagels 8. Jun 2017 11:19

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von bra (Beitrag 1373825)
Delphi-Quellcode:
var FString: String = 'Test';

procedure Change(const AString: String);
begin
  FString := 'Blubb';
  ShowMessage(AString);
end;

procedure CallMe;
begin
  Change(FString);
  Change(FString);
end;

Da frage ich mich.... wer baut so einen Unsinn?

Mavarik 8. Jun 2017 11:26

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von SneakyBagels (Beitrag 1373839)
Zitat:

Zitat von bra (Beitrag 1373825)
Delphi-Quellcode:
var FString: String = 'Test';

procedure Change(const AString: String);
begin
  FString := 'Blubb';
  ShowMessage(AString);
end;

procedure CallMe;
begin
  Change(FString);
  Change(FString);
end;

Da frage ich mich.... wer baut so einen Unsinn?

Jo... Wenn ich einen Referenz als Const übergebe und dann ne "GLOBALE" Variable intern ändere, muss ich mich nicht wundern...
Wie macht das den C? Den Zugriff auf die Globale Variable verhindern, weil das zufällig die gleiche Referenz ist?
Fehlermeldung beim compilieren? Oder etwa zur Laufzeit?

Mavarik

bra 8. Jun 2017 11:39

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von SneakyBagels (Beitrag 1373839)
Da frage ich mich.... wer baut so einen Unsinn?

Das war eigentlich nur ein Test, einen ähnlichen Code hatte ich irgendwo im Bezug auf diese Delphi-const-Geschichte gefunden. Dass der Code so Käse ist, ist mir schon klar. Seltsam ist nur das Ergebnis, da wird nämlich beim zweiten Aufruf ein Leerstring ausgegeben.

SneakyBagels 8. Jun 2017 11:41

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Wie macht das den C? (...) Fehlermeldung beim compilieren?
Eine Fehlermeldung beim Kompilieren wäre in zukünftigen Versionen von Delphi vielleicht nicht schlecht.

Zitat:

Das war eigentlich nur ein Test
Das weiß ich, keine Sorge :P

Ich handhabe es immer so, dass ich nur Variablen/Typen etc übergebe bei denen ich ganz genau weiß, dass ich diese in der Prozedur / Funktion nur lese und nicht schreibe.
Dann sollte eigentlich nichts schiefgehen.
Auch nutze ich das nur bei String und Typen. Zahlenwerte und Booleans ignoriere ich.

Mavarik 8. Jun 2017 11:49

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Ich denke Const ist nicht nur für die Performance, sondern auch (für mich) so einen Art Flag...

Signalisiert mir
Delphi-Quellcode:
Procedure Foo(Const AValue : Integer)
ändert nix an dem was ich Übergebe...
Genauso wie OUT klar kann man Var nehmen aber das verhalten wird eindeutiger...

SneakyBagels 8. Jun 2017 11:52

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von Mavarik (Beitrag 1373847)
Genauso wie OUT klar kann man Var nehmen aber das verhalten wird eindeutiger...

Der Name var hat mich eh schon immer gestört. Außerdem ist er total irreführend.

Der schöne Günther 8. Jun 2017 12:08

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von Mavarik (Beitrag 1373847)
Ich denke Const ist nicht nur für die Performance, sondern auch (für mich) so einen Art Flag...

Signalisiert mir
Delphi-Quellcode:
Procedure Foo(Const AValue : Integer)
ändert nix an dem was ich Übergebe...

Nö, für den Aufrufer ändert sich doch nichts. Wenn die Methode kein
Delphi-Quellcode:
const
hätte erhält sie lokal auf dem Stack eine Kopie des Parameters, aber was kümmert das den Aufrufer?

Mavarik 8. Jun 2017 12:38

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1373852)
Zitat:

Zitat von Mavarik (Beitrag 1373847)
Ich denke Const ist nicht nur für die Performance, sondern auch (für mich) so einen Art Flag...

Signalisiert mir
Delphi-Quellcode:
Procedure Foo(Const AValue : Integer)
ändert nix an dem was ich Übergebe...

Nö, für den Aufrufer ändert sich doch nichts. Wenn die Methode kein
Delphi-Quellcode:
const
hätte erhält sie lokal auf dem Stack eine Kopie des Parameters, aber was kümmert das den Aufrufer?

Also: Bei
Delphi-Quellcode:
Procedure Foo(Var AValue : integer)
könnte es sein, dass die procedure Foo AValue intern verändert. Um das raus zu bekommen, muss ich mir die Procedure anschauen... Wenn da jedoch
Delphi-Quellcode:
Procedure Foo(Const AValue : Integer)
steht, ist es klar, meine Variable bleibt erhalten... (Halte Dich jetzt nicht am Integer="Welchertyp auch immer" fest) (Abgesehen von Classen-Object-Inhalte die über Methoden verändert werden...)

Warum hat developer X Var geschrieben? Weil er nicht wollte, das die ganze Struktur einmal kopiert werden muss... (Der kannte kein Const) Ich habe selber noch Millionen Zeilen Source-Code mit Var statt Const.

Zacherl 8. Jun 2017 12:43

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Im Bezug auf Strings hatte ich vor kurzem schonmal auf eine ähnliche Frage geantwortet:
http://www.delphipraxis.net/1359775-post23.html

Zitat:

Zitat von Mavarik (Beitrag 1373841)
Wie macht das den C? Den Zugriff auf die Globale Variable verhindern, weil das zufällig die gleiche Referenz ist?

Nee, vor solchen Sachen schützt C einen auch nicht. Könnte ja auch gewollt sein, selbst wenn es wenig Sinn ergibt.

Zitat:

Zitat von Der schöne Günther (Beitrag 1373852)
Zitat:

Zitat von Mavarik (Beitrag 1373847)
Ich denke Const ist nicht nur für die Performance, sondern auch (für mich) so einen Art Flag...

Signalisiert mir
Delphi-Quellcode:
Procedure Foo(Const AValue : Integer)
ändert nix an dem was ich Übergebe...

Nö, für den Aufrufer ändert sich doch nichts. Wenn die Methode kein
Delphi-Quellcode:
const
hätte erhält sie lokal auf dem Stack eine Kopie des Parameters, aber was kümmert das den Aufrufer?

Ich glaube Mavarik geht es um den Aspekt des "self documenting code". Natürlich ändert sich die Variable auch ohne
Delphi-Quellcode:
const
nicht nach dem Funktionsaufruf, aber z.b. Objektparameter deklariere ich auch gerne mit
Delphi-Quellcode:
const
, um zu signalisieren, dass ich das Objekt nicht verändere (auch wenn das aufgrund der fehlenden const correctness von Delphi natürlich funktionieren würde).

Der schöne Günther 8. Jun 2017 12:56

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Ok ich wollte nur darauf hinaus dass ein
Delphi-Quellcode:
const
für den Aufrufer genauso viel aussagt wie kein
Delphi-Quellcode:
const
.

Aus Performance-Gründen haben wir das
Delphi-Quellcode:
const
drin wo geht, es als Doku für Arme zu nutzen dass man verspricht das übergebene Objekt nicht zu manipulieren wäre natürlich auch eine Möglichkeit. Leider ist es dafür zu spät. Wäre vielleicht wirklich eine gute Idee gewesen. Naja, für's nächste Projekt... ;-)

DeddyH 8. Jun 2017 13:02

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von SneakyBagels (Beitrag 1373849)
Der Name var hat mich eh schon immer gestört. Außerdem ist er total irreführend.

Inwiefern? Gut, man hätte es auch als InOut bezeichnen können, aber ob das immer alle auf Anhieb kapieren?

uligerhardt 8. Jun 2017 13:17

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von DeddyH (Beitrag 1373862)
Zitat:

Zitat von SneakyBagels (Beitrag 1373849)
Der Name var hat mich eh schon immer gestört. Außerdem ist er total irreführend.

Inwiefern? Gut, man hätte es auch als InOut bezeichnen können, aber ob das immer alle auf Anhieb kapieren?

Ich hab das implizit immer als "der Parameter ist variabel" interpretiert. Also scheint mir das halbwegs logisch, zumindest nicht "total irreführend".

p80286 8. Jun 2017 15:02

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Sobald const,var und out im Spiel sind, weiß ich, das nicht der Wert übergeben wird.
Aber das
Delphi-Quellcode:
var Myvariable
das gleiche ist wie
Delphi-Quellcode:
@Myvariable
muß ich mir immer wieder ins Bewußtsein holen. Meiner Meinung nach ist das nicht so Optimal.

Gruß
K-H

Sailor 8. Jun 2017 16:36

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Ehrlich gesagt, verstehe ich die Verwirrung nicht: Man googele doch bitte mal CallByValue, CallByReference und CallByName. Das sind uralte Techniken. Das CONST soll doch das bei CallByValue obligatorische Kopieren des Wertes auf den Stack verhindern, um den nicht unnötig vollzumüllen und macht daher nur bei komplexen Datenstrukturen sowie in Delphi bei Strings Sinn. VAR resp. OUT bedeuten dagegen CallByReference, d.h. es wird die Adresse übergeben und damit ist der Wert der Variablen außerhalb der Prozedur veränderbar. CallByName kennt Delphi glücklicherweise nicht. Das gab es in ALGOL60, mit teilweise verblüffenden Ergebnissen.

p80286 8. Jun 2017 22:40

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Ja klar ist das uralt, aber warum zum Teufel gibt es dann kein
Delphi-Quellcode:
refconst Myvalue
sondern nur ein
Delphi-Quellcode:
const Myvalue
? Wahrscheinlich dient es der Klarheit :mrgreen:

Gruß
k-H

uligerhardt 9. Jun 2017 07:30

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von p80286 (Beitrag 1373944)
Ja klar ist das uralt, aber warum zum Teufel gibt es dann kein
Delphi-Quellcode:
refconst Myvalue
sondern nur ein
Delphi-Quellcode:
const Myvalue
?

Es gibt
Delphi-Quellcode:
const [Ref]
(https://stackoverflow.com/a/19097044/1431618). Natürlich inkompatibel mit prior art (http://wiki.freepascal.org/FPC_New_F...meter_modifier).

jaenicke 9. Jun 2017 08:24

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von Namenloser (Beitrag 1373822)
Ja, kannst du. Es schadet zumindest nicht.

So pauschal ist das nicht richtig. Wenn der Parameter eine Interface-Referenz ist und als const deklariert ist, kommt es nicht gut, wenn man ein TXyz.Create dort direkt übergibt. Also ich meine ohne Zwischenvariable vom Typ des Interfaces.

Grund:
Durch das Create selbst wird logischerweise der Referenzzähler nicht erhöht, durch das const ist aber auch die Referenzzählung für den Parameter deaktiviert. Also steht der Referenzzähler auf 0. Übergibt nun der Konstruktor das Interface an eine weitere Routine mit Referenzzählung, wird die Referenz um 1 erhöht und wieder auf 0 gesetzt. Danach ist dann die Referenz ungültig.

Solange man sauber immer mit Zwischenvariablen arbeitet, ist aber alles in Ordnung. So einen Fehler findet man aber leider nicht unbedingt so schnell...

Mavarik 9. Jun 2017 10:29

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von Sailor (Beitrag 1373904)
Ehrlich gesagt, verstehe ich die Verwirrung nicht: Man googele doch bitte mal CallByValue, CallByReference und CallByName. Das sind uralte Techniken. Das CONST soll doch das bei CallByValue obligatorische Kopieren des Wertes auf den Stack verhindern, um den nicht unnötig vollzumüllen und macht daher nur bei komplexen Datenstrukturen sowie in Delphi bei Strings Sinn. VAR resp. OUT bedeuten dagegen CallByReference, d.h. es wird die Adresse übergeben und damit ist der Wert der Variablen außerhalb der Prozedur veränderbar. CallByName kennt Delphi glücklicherweise nicht. Das gab es in ALGOL60, mit teilweise verblüffenden Ergebnissen.

Nicht so ganz... Const ist auch ein CallbyReference, der verbotene Schreibzugriff wird über Compilermagic geregelt... Oder?

Mavarik

Zacherl 9. Jun 2017 13:02

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von Mavarik (Beitrag 1373979)
Nicht so ganz... Const ist auch ein CallbyReference, der verbotene Schreibzugriff wird über Compilermagic geregelt... Oder?

Das kommt drauf an. Bei trivialen Datentypen verhält sich
Delphi-Quellcode:
const
wie CallByValue:
Delphi-Quellcode:
Unit1.pas.45: A(X);
005CDEEF 8B45F8           mov eax,[ebp-$08] // CallByValue
005CDEF2 E8D9FFFFFF      call A // procedure A(X: Integer)
Unit1.pas.46: B(X);
005CDEF7 8D45F8           lea eax,[ebp-$08] // CallByReference
005CDEFA E8D5FFFFFF      call B // procedure B(var X: Integer)
Unit1.pas.47: C(X);
005CDEFF 8B45F8           mov eax,[ebp-$08] // CallByValue
005CDF02 E8D1FFFFFF      call C // procedure C(const X: Integer)
Bei komplexen Datentypen (Objekte, Records, Interfaces, Strings) dahingegen wie CallByReference (dann wird allerdings auch der Parameter, welcher komplett ohne
Delphi-Quellcode:
const
oder
Delphi-Quellcode:
var
deklariert wurde als CallByReference umgesetzt. Der einzige Unterschied zwischen
Delphi-Quellcode:
const
und "nichts" besteht hier wirklich nur in der Schreibschutzprüfung - welche wie du bereits vermutet hast - zur Compiletime umgesetzt wird):
Delphi-Quellcode:
Unit1.pas.52: A(X);
005CDEEF 8D45F4           lea eax,[ebp-$0c] // CallByReference
005CDEF2 E8D9FFFFFF      call A // procedure A(X: TStruct)
Unit1.pas.53: B(X);
005CDEF7 8D45F4           lea eax,[ebp-$0c] // CallByReference
005CDEFA E8D5FFFFFF      call B // procedure B(var X: TStruct)
Unit1.pas.54: C(X);
005CDEFF 8D45F4           lea eax,[ebp-$0c] // CallByReference
005CDF02 E8D1FFFFFF      call C // procedure C(const X: TStruct)
Hierbei ist Delphi sogar so klug, Records mit z.b. nur einem einzigen Integer Element trotzdem als trivialen Datentyp zu behandeln.

Die eigentliche Optimierung sieht man im Falle des Structs hier ganz schön (jeweils komplett leere Funktionen):
Delphi-Quellcode:
// procedure A(X: TStruct)
Unit1.pas.32: begin
005CDED0 55               push ebp
005CDED1 8BEC            mov ebp,esp
005CDED3 81C46CFEFFFF    add esp,$fffffe6c
005CDED9 56               push esi
005CDEDA 57               push edi
005CDEDB 8BF0             mov esi,eax
005CDEDD 8DBD6CFEFFFF    lea edi,[ebp-$00000194]
005CDEE3 B965000000       mov ecx,$00000065
005CDEE8 F3A5             rep movsd
Unit1.pas.34: end;
005CDEEA 5F              pop edi
005CDEEB 5E              pop esi
005CDEEC 8BE5             mov esp,ebp
005CDEEE 5D              pop ebp
005CDEEF C3               ret

// procedure B(var X: TStruct)
Unit1.pas.37: begin
005CDEF0 55               push ebp
005CDEF1 8BEC            mov ebp,esp
005CDEF3 51               push ecx
005CDEF4 8945FC          mov [ebp-$04],eax
Unit1.pas.39: end;
005CDEF7 59               pop ecx
005CDEF8 5D              pop ebp
005CDEF9 C3               ret

// procedure C(const X: TStruct)
Unit1.pas.42: begin
005CDEFC 55               push ebp
005CDEFD 8BEC            mov ebp,esp
005CDEFF 51               push ecx
005CDF00 8945FC          mov [ebp-$04],eax
Unit1.pas.44: end;
005CDF03 59               pop ecx
005CDF04 5D              pop ebp
005CDF05 C3               ret
Und bei Strings sieht die Sache ähnlich aus (ebenfalls jeweils komplett leere Funktionen):
Delphi-Quellcode:
// procedure A(X: String)
Unit1.pas.32: begin
005CDED0 55               push ebp
005CDED1 8BEC            mov ebp,esp
005CDED3 51               push ecx
005CDED4 8945FC          mov [ebp-$04],eax
005CDED7 8B45FC          mov eax,[ebp-$04]
005CDEDA E881BEE3FF      call @UStrAddRef
005CDEDF 33C0             xor eax,eax
005CDEE1 55               push ebp
005CDEE2 6803DF5C00       push $005cdf03
005CDEE7 64FF30           push dword ptr fs:[eax]
005CDEEA 648920           mov fs:[eax],esp
Unit1.pas.34: end;
005CDEED 33C0             xor eax,eax
005CDEEF 5A              pop edx
005CDEF0 59               pop ecx
005CDEF1 59               pop ecx
005CDEF2 648910           mov fs:[eax],edx
005CDEF5 680ADF5C00       push $005cdf0a
005CDEFA 8D45FC          lea eax,[ebp-$04]
005CDEFD E87ABDE3FF      call @UStrClr
005CDF02 C3               ret
005CDF03 E990B3E3FF      jmp @HandleFinally
005CDF08 EBF0             jmp $005cdefa
005CDF0A 59               pop ecx
005CDF0B 5D              pop ebp
005CDF0C C3               ret

// procedure B(var X: String)
Unit1.pas.37: begin
005CDF10 55               push ebp
005CDF11 8BEC            mov ebp,esp
005CDF13 51               push ecx
005CDF14 8945FC          mov [ebp-$04],eax
Unit1.pas.39: end;
005CDF17 59               pop ecx
005CDF18 5D              pop ebp
005CDF19 C3               ret

// procedure C(const X: String)
Unit1.pas.42: begin
005CDF1C 55               push ebp
005CDF1D 8BEC            mov ebp,esp
005CDF1F 51               push ecx
005CDF20 8945FC          mov [ebp-$04],eax
Unit1.pas.44: end;
005CDF23 59               pop ecx
005CDF24 5D              pop ebp
005CDF25 C3               ret

Mavarik 9. Jun 2017 13:24

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von Zacherl (Beitrag 1373995)
Das kommt drauf an. Bei trivialen Datentypen verhält sich
Delphi-Quellcode:
const
wie CallByValue:
Delphi-Quellcode:
Unit1.pas.45: A(X);
005CDEEF 8B45F8           mov eax,[ebp-$08] // CallByValue
005CDEF2 E8D9FFFFFF      call A // procedure A(X: Integer)
Unit1.pas.46: B(X);
005CDEF7 8D45F8           lea eax,[ebp-$08] // CallByReference
005CDEFA E8D5FFFFFF      call B // procedure B(var X: Integer)
Unit1.pas.47: C(X);
005CDEFF 8B45F8           mov eax,[ebp-$08] // CallByValue
005CDF02 E8D1FFFFFF      call C // procedure C(const X: Integer)

Gut... Mov und lea hat laut meiner x86 reference die gleiche Anzahl von Taktzyklen... Also egal... aber wenn es CallByValue ist - ist die nicht Beschreibbarkeit Compilermagic...?

Sailor 9. Jun 2017 13:48

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Nicht so ganz... Const ist auch ein CallbyReference, der verbotene Schreibzugriff wird über Compilermagic geregelt... Oder?
Nein, es ist so implementiert wie CallByReference. Don't mix the concept with ist realization. Der ganze Wirrwarr ließe sich verhindern durch die Festlegung, daß auf CallByValueParameter nur lesend zugegriffen werden kann, vulgo sie dürfen nicht als lokale Variable mißbraucht werden. Das hat sich natürlich keiner getraut, zweng der Abwärtskompatibilität. Dann hätte der Benutzer völlige Klarheit und der Compilerentwickler freie Hand, wie er das durchzieht. Das jetzige CONST in der Parameterliste ist doch eigentlich ein Implementierungshinweis an den Compiler: Du kannst hier einen Zeiger übergeben, den Stack minimieren, mußt aber Schreibzugriffe sperren. Afaik ist das aber schon dem Wirth im Ursprungspascal durchgerutscht.

Zacherl 9. Jun 2017 14:54

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von Mavarik (Beitrag 1374005)
Gut... Mov und lea hat laut meiner x86 reference die gleiche Anzahl von Taktzyklen... Also egal... aber wenn es CallByValue ist - ist die nicht Beschreibbarkeit Compilermagic...?

Genau, tatsächlich ist bei trivialen Datentypen das CallByValue sogar meist performanter, weil entsprechende Werte einfach in Registern liegen bleiben können, während der Wert für eine Referenz ja zwingend auf dem Stack oder dem Heap angesiedelt sein muss. Dementsprechend macht Delphi das hier schon ziemlich gut.

Das mit der Beschreibbarkeit ist auch korrekt. Das passiert komplett zur Compiletime - sowohl für CallByValue, als auch für CallByReference.

Namenloser 9. Jun 2017 18:21

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von jaenicke (Beitrag 1373964)
Zitat:

Zitat von Namenloser (Beitrag 1373822)
Ja, kannst du. Es schadet zumindest nicht.

So pauschal ist das nicht richtig. Wenn der Parameter eine Interface-Referenz ist und als const deklariert ist, kommt es nicht gut, wenn man ein TXyz.Create dort direkt übergibt. Also ich meine ohne Zwischenvariable vom Typ des Interfaces.

Grund:
Durch das Create selbst wird logischerweise der Referenzzähler nicht erhöht, durch das const ist aber auch die Referenzzählung für den Parameter deaktiviert. Also steht der Referenzzähler auf 0. Übergibt nun der Konstruktor das Interface an eine weitere Routine mit Referenzzählung, wird die Referenz um 1 erhöht und wieder auf 0 gesetzt. Danach ist dann die Referenz ungültig.

Solange man sauber immer mit Zwischenvariablen arbeitet, ist aber alles in Ordnung. So einen Fehler findet man aber leider nicht unbedingt so schnell...

Wenn das stimmt, ist das meiner Meinung nach ein Bug in Delphi. Ein Referenzzähler sollte immer mit 1 initialisiert sein, nicht mit 0.

himitsu 9. Jun 2017 19:03

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von Namenloser (Beitrag 1374078)
Wenn das stimmt, ist das meiner Meinung nach ein Bug in Delphi. Ein Referenzzähler sollte immer mit 1 initialisiert sein, nicht mit 0.

In soeinem Fall sollte Delphi besser eine (interne) lokale Variable generieren und Diese an den Parameter übergeben.

Und nein, denn wenn das schon zu Beginn 1 ist und man übergibt das Interface an eine Variable, dann wäre es danach 2.
Ist die Variable dann weg, wäre es aber immernoch 1 und würde niemals freigegeben.

Namenloser 9. Jun 2017 19:38

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von himitsu (Beitrag 1374089)
Zitat:

Zitat von Namenloser (Beitrag 1374078)
Wenn das stimmt, ist das meiner Meinung nach ein Bug in Delphi. Ein Referenzzähler sollte immer mit 1 initialisiert sein, nicht mit 0.

In soeinem Fall sollte Delphi besser eine (interne) lokale Variable generieren und Diese an den Parameter übergeben.

Das kommt auf dasselbe raus, was ich meine. Der Referenzzähler sollte immer bei 1 starten, denn irgendjemand muss ja eine Referenz auf das Objekt haben, ansonsten dürfte es gar nicht existieren. Und wenn es keine gibt, dann muss der Compiler eine generieren.

Ich habe in C schon manuelle Referenzzählung implementiert und dort habe ich es immer so gemacht:

Code:
typedef struct RefCounted {
    int refcount;
} RefCounted;

RefCounted* refcounted_new()
{
    RefCounted *obj = malloc(sizeof(RefCounted));
    obj->refcount = 1;
    return obj;
}

void refcounted_destroy(RefCounted *obj)
{
    free(obj);
}

void addref(RefCounted *obj)
{
    ++(obj->refcount);
}

void release(RefCounted *obj)
{
    --(obj->refcount);
    if (obj->refcount==0) {
        refcounted_destroy(obj);
    }
}


int main()
{
    RefCounted *obj = refcounted_new();
    // Hier KEIN addref(obj)

    blablabla_irgendwas_mit_obj_machen(obj);

    release(obj);
}
So sollte es der Compiler auch machen.

jaenicke 9. Jun 2017 20:04

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Das stimmt nicht, denn ein Objekt hat keine Interfacereferenzen.
Deshalb lässt sich das Problem nicht so einfach lösen.

himitsu 9. Jun 2017 20:45

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von jaenicke (Beitrag 1374097)
Das stimmt nicht, denn ein Objekt hat keine Interfacereferenzen.
Deshalb lässt sich das Problem nicht so einfach lösen.

Im ARC hat es das doch.

Wie gesagt, das Problem lässt sich sofort lösen, wenn der Compiler bei Übergabe von irgendwas an einen Const-Parameter eine Variable zwischenschaltet.
Immer wenn es da implizit von TObject zu Interface castet.

Bzw. bei
Delphi-Quellcode:
TestFunction(TSomething.Irgendwas.Create)
gibt es doch dieses Problem.
Bei
Delphi-Quellcode:
TestFunction(Something.GetInterface)
geht es, da Delphi aus diesem gemanagten Result einen Var-Parameter macht, welcher über eine generierte lokale Variable läuft.
Und bei
Delphi-Quellcode:
TestFunction(Something.GetObject)
würde ich jetzt das selbe Problem vermuten, aber hier ist man selber Schuld, da man Objekt- und gezählte Interfacereferenzen niemals vermischen sollte.

Delphi-Quellcode:
procedure TestFunction(const Reference: IInterface);

Namenloser 9. Jun 2017 21:44

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Zitat:

Zitat von jaenicke (Beitrag 1374097)
Das stimmt nicht, denn ein Objekt hat keine Interfacereferenzen.

Und?

Delphi-Laie 3. Aug 2018 15:13

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Entschuldigt bitte, daß ich dieses Thema reanimiere, aber ich fand keine Antwort auf meine Frage, und diese Diskussion paßt am besten.

In der Delphi-Hilfe steht, daß der Compiler bei (der Verwendung von) Konstantenpararametern den Code bei strukturierten und String-Parametern optimieren könne. Nur, was bedeutet "strukturiert"? Vermutlich bis wahrscheinlich das, was in C-Sprachen mit/als "struct" deklariert/definiert wird, also Records.

Lange Rede, zählen Arrays (die ja ebenfalls Daten strukturiert enthalten) auch zum Const-Optimierungspotential? Ich vermute, ja.

himitsu 3. Aug 2018 16:03

AW: Code Optimisation: Benutzung von const in prozedur-Köpfen
 
Jupp, mit strukturierten Typen sind Records gemeint,
also im Prinzip geht es hier um alle Typen, die größer als SizeOf(Pointer) sind.

Strings (LongStrings) und dynamische Arrays sind praktisch das Gleiche. (beim String sind noch paar versteckte Felder mit drin und bei dynamischen Arrays fehlt das CopyOnWrite, welches die StringTypen aber haben)
Ausnahme sind ShortStrings, welche ein statisches Array sind, also quasi ein Record.
Zweite Ausnahme ist der WideString, welches eine Kapselung des BSTR (MSDN-Library durchsuchenSysAllocString) sind.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:14 Uhr.

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