Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Datenkopie vom einen Record in ein anderes (https://www.delphipraxis.net/183467-datenkopie-vom-einen-record-ein-anderes.html)

p80286 12. Jan 2015 11:28

Datenkopie vom einen Record in ein anderes
 
Hallo zusammen,
ich hätte da mal eine Frage zum Kopieren von Daten zwischen zwei Records.

Delphi-Quellcode:
type
  tMyRecord1 : packed record
                 datum : tdatetime;
                 wert : integer;
                 feld : string[255];
               end;

var
  record1 : tMyrecord1;
  record2 : tMyrecord1;

// So funktioniert es immer
record1.datum:=record2.datum;
record1.wert:=record2.wert;
record1.feld:=record2.feld;
 
//so geht es auch
move(record2,record1,sizeof(tMyrecord));
aber was ist wenn ich
Delphi-Quellcode:
type
  tMyRecord1 : packed record
                 datum : tdatetime;
                 wert : integer;
                 feld : AnsiString;
               end;
oder
Delphi-Quellcode:
type
  tMyRecord1 : packed record
                 datum : tdatetime;
                 wert : integer;
                 feld : String;
               end;
verwende?
dann sollte doch mit einem
Delphi-Quellcode:
move(record2,record1,sizeof(tMyrecord));
nur die Stringadresse kopiert werden und Änderungen in
Delphi-Quellcode:
record2.feld
hätten gleichzeitig Änderungen in
Delphi-Quellcode:
record1.feld
zur Folge?
Oder liege ich da falsch?

Gruß
K-H

Der schöne Günther 12. Jan 2015 11:40

AW: Datenkopie vom einen Record in ein anderes
 
Ich verstehe nicht- Warum sollte man das tun? Record-Zuweisungen sind doch immer eine vollständige Kopie:

Delphi-Quellcode:
program Project16;

{$APPTYPE CONSOLE}

{$R *.res}

uses System.SysUtils;

type
   TMyRecord1 = packed record
      datum : tdatetime;
      wert : integer;
      feld : AnsiString;
   end;

var
   firstRecord, secondRecord:   TMyRecord1;

begin
  try
   firstRecord.datum := Now();
   firstRecord.wert := 42;
   firstRecord.feld := 'Hallo Welt';

   secondRecord := firstRecord;

   firstRecord.datum := 0.0;
   firstRecord.wert := 99;
   firstRecord.feld := 'Derp';

   WriteLn( DateTimeToStr(secondRecord.datum) );
   WriteLn(secondRecord.wert);
   WriteLn(secondRecord.feld);

  except
   on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  readln;
end.

bernau 12. Jan 2015 11:50

AW: Datenkopie vom einen Record in ein anderes
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1286315)
Ich verstehe nicht- Warum sollte man das tun? Record-Zuweisungen sind doch immer eine vollständige Kopie:

Weil ein String erst mal ein Pointer auf einen Speicherbereich ist und du nur den Pointer kopierst. Damit zeigen die Strings von beiden Records auf den gleichen Speicherbereich. Änderst du den einen Record, dann wird der Zweite direkt mit geändert.

Bei records habe ich es mir angewöhnt immer eine Assign-Procedure einzubauen.

Ich scheue "move" wie der Teufel das Weihwasser.

Delphi-Quellcode:
type
    TMyRecord1 = packed record
       datum : tdatetime;
       wert : integer;
       feld : AnsiString;
       Procedure assign(aSource:TMyRecord1);
    end;

implementation

Procedure assign(aSource:TMyRecord1);
begin
  datum := aSource.adatum;
  wert := aSource.wert;
  feld := aSource.feld;
end;

mkinzler 12. Jan 2015 11:58

AW: Datenkopie vom einen Record in ein anderes
 
Komischerweise passiert das bei dem Beispiel nicht ;)

Der schöne Günther 12. Jan 2015 12:01

AW: Datenkopie vom einen Record in ein anderes
 
Eben. Da wir hier AnsiStrings haben geht es wohl um Windows. Strings sind Copy on Write. Wenn sich ein String ändert, ändert er nur den Pointer und lässt diesen nun auf einen neuen Speicherbereich zeigen.

bernau 12. Jan 2015 12:21

AW: Datenkopie vom einen Record in ein anderes
 
Zitat:

Zitat von mkinzler (Beitrag 1286317)
Komischerweise passiert das bei dem Beispiel nicht ;)

:oops:

Dennoch versuche ich das Kopieren von Speicherbereichen zu vermeiden.:lol:

p80286 12. Jan 2015 12:26

AW: Datenkopie vom einen Record in ein anderes
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1286318)
Eben. Da wir hier AnsiStrings haben geht es wohl um Windows. Strings sind Copy on Write. Wenn sich ein String ändert, ändert er nur den Pointer und lässt diesen nun auf einen neuen Speicherbereich zeigen.

D.h. mit "meinen move" liege ich auf der sicheren Seite?
Nicht daß wir uns falsch verstehen, eigentlich bevorzuge ich Pointer (da weiß man was man hat) aber wenn nur Werte vorhanden sínd/übergeben werden ist eine narrensichere allgemeingültige Verfahrennsweise ganz angenehm.

Gruß
K-H

Der schöne Günther 12. Jan 2015 12:29

AW: Datenkopie vom einen Record in ein anderes
 
Ich finde, bei reinen Pointern weiß man eigentlich nicht im geringsten mehr was man hat. :-D Wenn die Motivation ist, einen Record zu kopieren reicht
Delphi-Quellcode:
meineKopie := einAndererRecord;
Narrensicherer geht es doch nicht ;-)

Auch:
Ich habe in meinem Leben noch nie Move(..) benutzt- String ist doch schon ein "managed" Type: Er hat einen Referenzzähler. Allein den machst du dir mit einer reinen Byte-Kopie schon kaputt: Er ist um eins zu niedrig.

Mavarik 12. Jan 2015 12:37

AW: Datenkopie vom einen Record in ein anderes
 
NEIN!

Der Move von Records mit dynamischen Elementen ist i.d.R. falsch, da wie due geschrieben hast nur die Pointer kopiert werden.

Ein

Delphi-Quellcode:
SecondRecord := FirstRecord;
Macht intern eigentlich ein

Delphi-Quellcode:
SecondRecord.Feld := FirstRecord.Feld; // Natürlich für alle Elemente
Bei einer Zuweisung eines Records auf einen anderen, will man doch den Inhalt kopieren und nicht die Referenz...

Daher ist ein Assign nicht nötig...

Mavarik

himitsu 12. Jan 2015 12:43

AW: Datenkopie vom einen Record in ein anderes
 
Um es nochmal klar zu erwähnen:

Ich rate grundsätzlich von Move und Co. ab (außer wenn es wirklich nicht anders geht, aber wenn, dann muß man ganz genau aufpassen was man da für Mist verzapft)

Und für die Zuweisung zweier Records, von gleichem/kompatiblem Typ, ist das garnicht nötig, da die Zuweisung via
Delphi-Quellcode:
:=
alles Wichtige erledigt.
Vorallem bezüglich der Referenzzählung von LongStrings, dynamischen Arrays, Interfaces, Variants usw.

Ein ShortString (z.B.
Delphi-Quellcode:
string[255]
) ist wie ein Record, statisches Array oder einfach gesagt wie ein Integer anzusehn und bereitet die wenigsten Probleme, unter den Strings.

Zitat:

dann sollte doch mit einem move(record2,record1,sizeof(tMyrecord)); nur die Stringadresse kopiert werden und Änderungen in
record2.feld hätten gleichzeitig Änderungen in record1.feld zur Folge?
Oder liege ich da falsch?
Ja, aber vorallem schrottest du damit die automatische Speicherverwaltung (des
Delphi-Quellcode:
String
) und alles ist im Arsch.


Wer unbedingt einen "Move"-Befehl verwenden will, der hat dafür New/Initialize/InitializeRecord/InitializeArray, Dispose/Finalize/FinalizeRecord/FinalizeArray und Copy/CopyArray/CopyRecord aus der System-Unit verwenden.

p80286 12. Jan 2015 13:03

AW: Datenkopie vom einen Record in ein anderes
 
Zitat:

Zitat von himitsu (Beitrag 1286324)
Und für die Zuweisung zweier Records, von gleichem/kompatiblem Typ, ist das garnicht nötig, da die Zuweisung via
Delphi-Quellcode:
:=
alles Wichtige erledigt.
Vorallem bezüglich der Referenzzählung von LongStrings, dynamischen Arrays, Interfaces, Variants usw.

Hey, das war's. Aus irgendwelchen Gründen hatte ich im Kopf, daß das
Delphi-Quellcode:
:=
mit Records nicht funktioniert

und natürlich an alle anderen auch vielen Dank!

Irgendwann werd' auch ich die Stringmagie verstehen, und nichts ist besser als Pointer! (wenn man weiß was man tut)

Vielen Dank nochmals
K-H

himitsu 12. Jan 2015 13:09

AW: Datenkopie vom einen Record in ein anderes
 
In aktuelleren Delphis wurde die OH überarbeitet. (k.A. wann genau)
Und man kann da ganz genau nachlesen wie die Strings intern Funktionieren. (falls man das nicht persönlich in der System.pas erkunden will)

Der schöne Günther 12. Jan 2015 13:31

AW: Datenkopie vom einen Record in ein anderes
 
Aber das habe ich doch ganz am Anfang direkt gesagt?

Niemand nimmt mich ernst.

bernau 12. Jan 2015 13:44

AW: Datenkopie vom einen Record in ein anderes
 
Zitat:

Zitat von Mavarik (Beitrag 1286323)
Daher ist ein Assign nicht nötig...

Richtig. Aber vorausschauend schon. Sollte der Record aus irgend einem Grunde (Mit einem Object o.ä. erweitert werden, dann muss ich mich um die Zuweisung nicht mehr kümmern. Nur noch im Assign.

Sir Rufo 12. Jan 2015 13:51

AW: Datenkopie vom einen Record in ein anderes
 
Zitat:

Zitat von bernau (Beitrag 1286335)
Zitat:

Zitat von Mavarik (Beitrag 1286323)
Daher ist ein Assign nicht nötig...

Richtig. Aber vorausschauend schon. Sollte der Record aus irgend einem Grunde (Mit einem Object o.ä. erweitert werden, dann muss ich mich um die Zuweisung nicht mehr kümmern. Nur noch im Assign.

Und was willst du im Assign anders machen als die Objekt-Referenz kopieren (was die normale Zuweisung eben auch macht)

himitsu 12. Jan 2015 14:52

AW: Datenkopie vom einen Record in ein anderes
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1286333)
Niemand nimmt mich ernst.

https://www.besamex.de/bachblueten-m...-09706670.html

p80286 12. Jan 2015 15:07

AW: Datenkopie vom einen Record in ein anderes
 
@den schönsten aller Männer
Doch wir nehmen Dich ernst, aber laß die Finger von den Bachblüten, die bekommt unser Hund wenn wir auf Reisen gehen:drunken:

Gruß
K-H

bernau 12. Jan 2015 15:16

AW: Datenkopie vom einen Record in ein anderes
 
Zitat:

Zitat von Sir Rufo (Beitrag 1286337)
Und was willst du im Assign anders machen als die Objekt-Referenz kopieren (was die normale Zuweisung eben auch macht)

Evtl. Schauen, ob beim Zielrecord schon ein initialisiertes Objekt im Feld vorhanden ist und dann nicht einfach den Pointer überschreiben.

Mavarik 12. Jan 2015 15:18

AW: Datenkopie vom einen Record in ein anderes
 
Zitat:

Zitat von bernau (Beitrag 1286335)
Richtig. Aber vorausschauend schon. Sollte der Record aus irgend einem Grunde (Mit einem Object o.ä. erweitert werden, dann muss ich mich um die Zuweisung nicht mehr kümmern. Nur noch im Assign.

Eigentlich macht das "NIE" Sinn...

Wenn Du mal den Record einem anderen zuweisen musst nimmst Du den IMPLIZIET Operator und kannst alles da drin machen.

Zitat:

Zitat von bernau (Beitrag 1286345)

Evtl. Schauen, ob beim Zielrecord schon ein initialisiertes Objekt im Feld vorhanden ist und dann nicht einfach den Pointer überschreiben.


Nur wenn Du Feldinhalte ändern willst... Sonst klingt das mehr nach dem Ruf eines Interfaces... [EDIT]

bernau 12. Jan 2015 15:38

AW: Datenkopie vom einen Record in ein anderes
 
Zitat:

Zitat von Mavarik (Beitrag 1286346)
Wenn Du mal den Record einem anderen zuweisen musst nimmst Du den IMPLIZIET Operator und kannst alles da drin machen.

Gibt's das auch schon in Delphi 2007? :wink:

EDIT: Anscheinend schon. Habe es allerdings noch nie wirklich gesehen. (Ich hab's übersehen)

DeddyH 12. Jan 2015 15:42

AW: Datenkopie vom einen Record in ein anderes
 
Das gibt' s IIRC seit Delphi 2006.

Sir Rufo 12. Jan 2015 17:25

AW: Datenkopie vom einen Record in ein anderes
 
Zitat:

Zitat von bernau (Beitrag 1286345)
Zitat:

Zitat von Sir Rufo (Beitrag 1286337)
Und was willst du im Assign anders machen als die Objekt-Referenz kopieren (was die normale Zuweisung eben auch macht)

Evtl. Schauen, ob beim Zielrecord schon ein initialisiertes Objekt im Feld vorhanden ist und dann nicht einfach den Pointer überschreiben.

Warum nicht die Referenz einfach überschreiben? Der Record eignet sich doch eh nicht zur Lifetime-Verwaltung einer Objekt-Instanz. Vergisst du den Record passiert einfach nichts (gut der wird finalisiert, aber die Instanz wird nicht freigegeben).

Und dann werden die Felder eines Records nur bei einem gemanagten Typen initialisiert. Und eine Objekt-Instanz ist erst mit ARC gemanaget.
Delphi-Quellcode:
TFoo = record
  Instance : TObject; // ohne Zuweisung kann hier alles drin stehen!
  Str : string; // init mit ''
  Intf : IInterface; // init mit nil
  procedure Assign( Other : TFoo );
end;

procedure TFoo.Assign( Other : Tfoo );
begin
  if Assigned( Instance ) then
    FreeAndNil( Instance ); // das knallt wie ein Zufallsgenerator!
  Instance := Other.Instance;


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:19 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