Autor Beitrag
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: Di 23.10.12 16:22 
Hallo Delphifreunde!

Derzeit bin ich dabei, eine weitere Langzahlenbibliothek (uBigIntsV3 aus der DFFLibV14) in meinen Langzahlentaschnerechner zu integrieren.

Die Rechenfunktionen werden dort als Klassenprozeduren bereitgestellt, z.B.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
type
  TDigits = array of int64;

  TInteger = class(TObject)
  protected
    Sign:    integer;
    fDigits: TDigits;
    Base:    integer;
  .
  .
  .   
  public
    procedure Add(const I2: TInteger); overload;
.

Zur flexiblen Handhabung - und auch zur Verschachtelung bei komplexeren Berechnungen - benötige ich jedoch Funktionen. Ein richtiges Ergebnis erhalte ich z.B. mit

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
function TI_Add(const i1,i2:TInteger):TInteger;
begin
result:=i1;
result.add(i2)
//oder:
//i1.Add(i2);
//result:=i1
end;


, aufgerufen z.B. so:

ausblenden Delphi-Quelltext
1:
Num3:=TI_add(Num1,Num2)					


Das Fatale: Sogar, wenn man beide Argumente in der Zielfunktion TI_Add als konstant deklariert sind, wird das erste Argument (Num1) im Ergebnis dieses Funktionsaufrufes verändert, also auch aus der Positionen derjenigen übergeordneten Funktion, aus der diese Kapselfunktion aufgerufen wird! Das ist zum Mäusemelken! Ich finde dafür keine Erklärung, weil der dortige Datentyp TInteger keine "verzeigerte" Datenstruktur ist. Ein Pointer mag ja konstant bleiben, aber der Inhalt der Adresse, auf die er hinzeigt, nicht, und schon verändern sich Inhalte, die darauf zeigen, doch diesen Fall kann ich hier nicht erkennen.

Bisherige funktionierende Abhilfe: Ich übergebe statt der Langzahl des Typs "TInteger" einen String und konvertiere diesen erst in die Kapselfunktion:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
function TI_Add(i1:string;i2:TInteger):TInteger;
begin
result:=ConvertStringToTI(i1);
result.add((i2))
end;


, doch das ist unelegant und ganz sicher gerade bei größeren/längeren Zahlen auch erheblich geschwindigkeitsmindernd.

Bei MPA von gammatester bekam ich das gleiche Problem gelöst, hier jedoch bisher nicht.

Kennt jemand den Grund, warum die Argumente in der übergeordneten Ebene nicht konstant bleiben und ggf. einen eleganteren Weg, die aufrufenden Argumente unbehelligt zu lassen?

Danke im voraus!


Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Di 23.10.2012 um 18:21
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 23.10.12 16:36 
Variablen vom Typ TInteger sind Pointer, denn das ist eine Klasse. Und eine Variable dieses Typs ist immer ein Zeiger auf ein Objekt von diesem Typ.

Hier eignen sich auch Records viel besser, da diese (in einigermaßen aktuellen Delphiversionen, ab Delphi 2006) mit Klassenoperatoren sehr viel komfortabler nutzbar sind. Zudem lieferst du ja sonst Objekte zurück, und das führt nur zu Speicherlecks. (Das kann man natürlich mit Interfaces vermeiden.)

Für diesen Beitrag haben gedankt: Delphi-Laie
Delphi-Laie Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: Di 23.10.12 20:18 
Danke, Sebastian!

"Irgendwie" ahnte ich das ja schon anhand des Verhaltens. So wundert es mich jetzt nicht. Diese elenden Zeiger....ich mag sie bis heute nicht...schön schnell, aber man muß eben wissen bzw. aufpassen, welche Seiteneffekte sie auslösen.

Werde ich also meine "Bastellösung" als Notbehelf (langsam und unelegant) oder es mit Records versuchen. Eigentlich schade, denn die Prozeduren sind verdammt schnell, schneller noch, als mir gammatesters MPA schon in der Hinsicht positiv auffiel (und derzeitiger Spitzenreiter ist, von Hagen Redmanns geheimer Verschlußsache einmal abgesehen).
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 24.10.12 06:15 
user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Diese elenden Zeiger....ich mag sie bis heute nicht...schön schnell, aber man muß eben wissen bzw. aufpassen, welche Seiteneffekte sie auslösen.
Ohne würde aber vieles schlicht gar nicht funktionieren, du merkst nur nicht wo du die überall implizit nutzt.
Für eine Kopie eines Objekts musst du eben ein neues erstellen und die Daten übernehmen. Nur dass du dann eben Speicherlecks hast. Aber wenn du wie gesagt Interfaces benutzt, hast du das Problem nicht.

Aber mal ein Beispiel warum Records wirklich Sinn machen (Delphi 2006+ wie geschrieben):
ausblenden volle Höhe 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:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
type
  TInteger = record
    Value: Integer; // nur als Beispiel
    class operator Add(const Value1, Value2: TInteger): TInteger;
    class operator implicit(const Value: String): TInteger;
    class operator implicit(const Value: TInteger): String;
    class operator implicit(const Value: Integer): TInteger;
  end;

class operator TInteger.Add(const Value1, Value2: TInteger): TInteger;
begin
  Result.Value := Value1.Value + Value2.Value;
end;

class operator TInteger.implicit(const Value: String): TInteger;
begin
  Result.Value := StrToInt(Value);
end;

class operator TInteger.implicit(const Value: TInteger): String;
begin
  Result := IntToStr(Value.Value);
end;

class operator TInteger.implicit(const Value: Integer): TInteger;
begin
  Result.Value := Value;
end;

// Und nun kannst du den Typ benutzen:
var
  a, b: TInteger;
begin
  a := 5;
  b := '10';
  ShowMessage(a + b); // angezeigt wird 15
end;

Für diesen Beitrag haben gedankt: Delphi-Laie
Delphi-Laie Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: Mi 24.10.12 08:45 
Das ist hervorragend, große Klasse und tausend Dank!

Jetzt nur noch eine Frage: Was sind

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Interfaces
?

Das Wort "interface" ist ja ein Schlüsselwort und hat erstmal überhaupt nichts mit Typen, Variablen o.ä. zu tun.

Gruß Delphi-Laie
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 24.10.12 09:28 
ausblenden 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:
type
  IInteger = interface
    procedure SetValue(const AValue: Integer);
    function GetValue: Integer;
    property Value: Integer read GetValue write SetValue;
  end;

  TInteger = class(TInterfacedObject, IInteger)
  private
    procedure SetValue(const AValue: Integer);
    function GetValue: Integer; 
  public
    class function Add(const AValue1, AValue2: IInteger): IInteger;
    constructor Create(const AValue: Integer);
    property Value: Integer read GetValue write SetValue;
  end;

...

class function TInteger.Add(const AValue1, AValue2: IInteger): IInteger;
begin
  Result := TInteger.Create(AValue1.Value + AValue2.Value);
end;
Da du nun ein Interface als Ergebnis hast, wird das automatisch freigegeben, wenn es nicht mehr benutzt wird (wenn die Variable aus dem Scope läuft).

Für diesen Beitrag haben gedankt: Delphi-Laie
Delphi-Laie Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: Mi 24.10.12 12:54 
Neben dem Druck auf den Dank-Knopf jetzt auch noch mal ein Dank extra! Hast eben Deine vielen hundert Danks nicht zufällig.