Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Frage zu Variant


Jerk - Fr 04.07.08 00:28
Titel: Frage zu Variant
Ich bin grade dabei eine Art Werkzeugunit zu erstellen, darunter ist auch eine Procedur namens "XCopy".

Was diese machen soll ist recht simpel, sie soll beim Aufruf also XCopy(@x,@y); die Werte von x und y tauschen, jedoch unabhängig ob x und y string,integer,boolean oder sonstewas sind, weshalb ich den Datentyp Variant gewählt habe.

Erstmal die Procedure

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
 procedure XCopy(Var1,Var2 : PVariant);
 var
  Buffer : Variant;
 begin
  Buffer := Var1^;
  Var1^  := Var2^;
  Var2^  := Buffer;
 end;

...
// Aufruf:

XCopy(@X,@Y);


Exception-Klasse EVariantBadVarTypeError mit Meldung 'Invalid variant type'.


Dazu meine Frage, wäre es besser mehrere Überladene Versionen für die einzelnen Datentypen anzufertigen oder wie kann ich das Anstellen.
Bzw. wie kann ich denn die Variable ohne @ übergeben, ähnlich wie bei inc(x,1); ???


platzwart - Fr 04.07.08 02:27


Delphi-Quelltext
1:
procedure XCopy(var Var1,Var2 : PVariant);                    


das "var" gibt an, dass nicht die übergebenen werte geändert, sondern die übergebenen variablen verändert (überschrieben) werden sollen...


Tilman - Fr 04.07.08 02:34

Also bei mir funzt alles ganz wunderbar. Sowohl die Version mit den Zeigern, als auch die referenzvariablen-Version von Platzwart. Kein Fehler zu sehen.

@Jerk zeig mal genau wie du das aufrufst und wo der Fehler auftritt.

// edit sehe grade, @platzwart: du darfst in deiner Version dann aber natürlich nicht PVariant nehmen sondern Variant selbst. Denn darauf werden ja eh Referenzen übergeben, muss also nicht nochmal "manuell" gemacht werden ;)


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
 procedure XCopy(var Var1,Var2 : Variant);
 var
  Buffer : Variant;
 begin
  Buffer := Var1;
  Var1  := Var2;
  Var2  := Buffer;
 end;


platzwart - Fr 04.07.08 02:43

user profile iconTilman hat folgendes geschrieben:

// edit sehe grade, @platzwart: du darfst in deiner Version dann aber natürlich nicht PVariant nehmen sondern Variant selbst. Denn darauf werden ja eh Referenzen übergeben, muss also nicht nochmal "manuell" gemacht werden ;)


korrekt


Jerk - Fr 04.07.08 03:23

Jo das geht, vielen Dank!!


alzaimar - Fr 04.07.08 09:12

:mahn: Wobei ich noch anmerken möchte, das 'XCpopy' kein guter Name für die Prozedur ist. 'Exchange' wäre besser. Weiterhin baust Du eine nicht unerhebliche Performancebremse ein.


Tilman - Fr 04.07.08 10:17

I wo, Xcopy ist super, wer benutzt denn heute noch M$-DOS ^^

Ich plädiere für "Swap()". Gibts zwar schon, aber könnte man ja vielleicht überladen.


Jerk - Mo 07.07.08 22:11

user profile iconalzaimar hat folgendes geschrieben:
:mahn: Wobei ich noch anmerken möchte, das 'XCpopy' kein guter Name für die Prozedur ist. 'Exchange' wäre besser. Weiterhin baust Du eine nicht unerhebliche Performancebremse ein.


Deswegen meine Frage, wäre überladen besser gewesen?


Delete - Mo 07.07.08 22:54

user profile iconalzaimar hat folgendes geschrieben:
:mahn: Wobei ich noch anmerken möchte, das 'XCpopy' kein guter Name für die Prozedur ist. 'Exchange' wäre besser. Weiterhin baust Du eine nicht unerhebliche Performancebremse ein.


geb dir recht XCopy ist Kacke.. das heisst dass man die zwei elemente irgendwo hin kopieren möcht, was die procedure allerdings nicht macht ... sondern sie vertauscht die werte ... :eyecrazy:

aber um zu variant zurückzukommen, weiss zwar nicht, wie du auf den trichter kommst, aber die umsetzung ist reichlich dämlich... nimm lieber 'n paar funktionen/proceduren überlade sie und optimiere darin den code ... dann hast du was ordentliches :-)


Timosch - Di 08.07.08 16:57

Kann man nicht auch irgendwie Parameter als void oder so deklarieren? Wenn ich SizeOf verwende, kommt z.B. immer als Hilfe "Kein Typ angegeben" oder so...


Yogu - Di 08.07.08 17:15

user profile iconTimosch hat folgendes geschrieben:
Kann man nicht auch irgendwie Parameter als void oder so deklarieren? Wenn ich SizeOf verwende, kommt z.B. immer als Hilfe "Kein Typ angegeben" oder so...


Delphi-Quelltext
1:
procedure Exchange(var Var1, Var2);                    

Das Problem dabei ist, dass du dann die beiden Variablen nicht mehr wirklich austauschen kannst, weil du ja keinen Typ hast, den du als Puffer verwenden kannst. Es sei denn, du willst nur die Adressen austauschen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure Exchange(var Var1, Var2);
var Buffer: Pointer;
begin
  Buffer := @Var1;
  Var2 := Var1;
  Var1 := Buffer^;
end;

Ich hab keine Ahnung, ob das funktioniert ;)


alzaimar - Di 08.07.08 18:51

Nein, funktioniert nicht. Man kann einen untypisierten Zeiger (Pointer) nicht dereferenzieren. Wohin auch? So ein allgemeingültiger Vertausch-O-Mat kann nicht funktionieren, denn spätestens bei Objekten legt er sich die Karten. Bei einfachen Typen müsste man die Datentypgröße mit angeben und dann mit MoveMemory arbeiten.


Tilman - Di 08.07.08 21:02

Ich denke auch, es ist ganz interessant um mal zu sehen was so alles möglich ist - aber wirklich zum verwenden eher ungeeignet.


jaenicke - Mi 09.07.08 11:09

user profile iconalzaimar hat folgendes geschrieben:
Nein, funktioniert nicht. Man kann einen untypisierten Zeiger (Pointer) nicht dereferenzieren. Wohin auch? So ein allgemeingültiger Vertausch-O-Mat kann nicht funktionieren, denn spätestens bei Objekten legt er sich die Karten. Bei einfachen Typen müsste man die Datentypgröße mit angeben und dann mit MoveMemory arbeiten.
Warum eigentlich? Dereferenzieren ist hier ja auch gar nicht nötig. Schließlich sind die Variablen doch im Grunde Zeiger auf das jeweilige Objekt, d.h. wenn ich zwei gleiche Objekte habe (worum es hier ja geht), dann genügt es doch den Zeiger entsprechend auf das jeweils andere Objekt zeigen zu lassen, oder?
Was ich nicht weiß ist, ob das die Referenzcounter durcheinanderbringt, weil ich mir nie angeschaut habe wie die implementiert sind, aber eigentlich werden die ja im Objekt gespeichert und die Anzahl der darauf zeigenden Pointer ändert sich ja nicht. (Bei untypisierten Zugriffen können die Referenzcounter ja nicht aktualisiert werden, das zur Erklärung, weshalb ich darüber nachgedacht habe.) Aber dazu kannst du ja vermutlich was sagen, was da (evtl. falsch) passiert.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure TForm75.Button1Click(Sender: TObject);

  procedure ExchangePointer(var x1, x2: Pointer);
  var
    tmp: Pointer;
  begin
    tmp := x1;
    x1 := x2;
    x2 := tmp;
  end;

begin
  ExchangePointer(Pointer(Edit1), Pointer(Edit2));
  ShowMessage(Edit2.Text);
end;
Funktionieren tut es soweit, es gibt auch keine Abstürze. Mir fielen jetzt auch keine negativen Effekte ein, die sich daraus ergeben könnten.

Für einfache Datentypen dann dazu noch überladene Versionen, dann sollte alles abgedeckt sein.