Board index » delphi » Copying an object with Move raises an exception

Copying an object with Move raises an exception

I have been attempting to copy an object with the move command.  This works
until the variable used as the source in the move statement is released.
This causes the destination variable to be corrupted. To me this defies the
idea of a copy.  I am enclosing sample code.

Many thanks in advance.

  - Dan
  12/26/98 4:19:22 PM
----------------------------
unit frmMoveTest;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
 TTestObj = Class(TObject)
      public
       AValue: String;
      end;

  TForm1 = class(TForm)
  Button1: TButton;
  procedure Button1Click(Sender: TObject);
  private
  { Private declarations }
  public
  { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
 tobSource,
  tobDest: TTestObj;
begin
 tobSource := TTestObj.Create;
 tobSource.AValue := 'Testing...';
 Move(tobSource, tobDest, SizeOf(tobDest));
 ShowMessage('This value will display fine: ' + tobDest.AValue);
 tobSource.Free;
 ShowMessage('Even though the tobDest variable has not been released, this '
+
  'line results in an exception: ' + tobDest.AValue);
end;

end.

 

Re:Copying an object with Move raises an exception


Dan,

Quote
>I have been attempting to copy an object with the move command.  This works
>until the variable used as the source in the move statement is released.
>This causes the destination variable to be corrupted. To me this defies the
>idea of a copy.  I am enclosing sample code.

>procedure TForm1.Button1Click(Sender: TObject);
>var
> tobSource,
>  tobDest: TTestObj;
>begin
> tobSource := TTestObj.Create;
> tobSource.AValue := 'Testing...';
> Move(tobSource, tobDest, SizeOf(tobDest));
> ShowMessage('This value will display fine: ' + tobDest.AValue);
> tobSource.Free;
> ShowMessage('Even though the tobDest variable has not been released, this
'
>+
>  'line results in an exception: ' + tobDest.AValue);
>end;

You probably think you're copying objects, but you're not. tobSource and
tobDest are *references* to objects. So what you're doing is copying the
references, not the actual objects. Your code does exactly the same as:
tobDest := tobSource;

So, when you call tobSource.Free, tobDest is a reference to an object that
has been freed, therefor, you get an AccessViolation...

Take a look at the Assign method in the help file, I think this is what
you're looking for.

HTH,

        Niels.

--------------------------------------------
Niels Vanspauwen
Student @ KULeuven
Faculty of Engineering
Department of Computer Science
--------------------------------------------
Author of the most powerful macro-component for all your
Delphi-applications.
TMagicMacros records, plays, shows infoboxes, supports VisualHelp, and much
more!
Check out: http://magicmacros.8m.com

Re:Copying an object with Move raises an exception


Quote
Dan Richardson wrote:

> I have been attempting to copy an object with the move command.  This works
> until the variable used as the source in the move statement is released.
> This causes the destination variable to be corrupted. To me this defies the
> idea of a copy.  I am enclosing sample code.
> type
>  TTestObj = Class(TObject)
>       public
>        AValue: String;
>       end;

>   TForm1 = class(TForm)
>     Button1: TButton;
>     procedure Button1Click(Sender: TObject);
>   end;

> var
>   Form1: TForm1;

> implementation

> {$R *.DFM}

> procedure TForm1.Button1Click(Sender: TObject);
> var
>  tobSource,
>   tobDest: TTestObj;
> begin
>  tobSource := TTestObj.Create;
>  tobSource.AValue := 'Testing...';
>  Move(tobSource, tobDest, SizeOf(tobDest));

You are copying a single pointer here. tobDest is a POINTER!!!!
Though it is hidden in the "DELPHI" kind of Pascal source code.

Quote
>  ShowMessage('This value will display fine: ' + tobDest.AValue);
>  tobSource.Free;

Here you free the ONLY EXISTING object.

Quote
>  ShowMessage('Even though the tobDest variable has not been released, this '
> +
>   'line results in an exception: ' + tobDest.AValue);

I really do not understand which devil was riding those Delphi inventors
to hide the pointer properties of pointers. It makes soooo much troubles
and it has soooo little benefit to save a few keystrokes to enter the ^.

It does not help, you have to learn Pascal earlier or later, if you
want to understand the silly behaviour of Delphi.

http://www.geocities.com/SiliconValley/2926/tpsrc/tpmem.html
is a Pascal pointer primer, I added a few paragraphs concerning
Delphi last night.

Regards, Franz Glaser

Re:Copying an object with Move raises an exception


Niels,

Many thanks for your response.

Quote
>> You probably think you're copying objects, but you're not. tobSource and

tobDest are *references* to objects. So what you're doing is copying the
references, not the actual objects. Your code does exactly the same as:
tobDest := tobSource;

So, when you call tobSource.Free, tobDest is a reference to an object that
has been freed, therefor, you get an AccessViolation...

Take a look at the Assign method in the help file, I think this is what
you're looking for. <<

Given the errors I was getting, I thought that Move must be doing a pointer
copy.  Your'e right, what I want is the equivalent of Assign.  I tried to
use it and while it's not available on TObject, it is available on
TPersistent so I changed the class of TTestObj.  The problem is when I use
assign, I get an EConverError exception 'Cannot assign a TTestObj to a
TTestObj.'  This is what happens when I run the code sample shown below.

Many thanks for any thoughts or suggestions.

- Dan
-----------------------
unit frmMoveTest;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
 TTestObj = Class(TPersistent)
      public
       AValue: String;
      end;

  TForm1 = class(TForm)
  Button1: TButton;
  procedure Button1Click(Sender: TObject);
  private
  { Private declarations }
  public
  { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
 tobSource,
  tobDest: TTestObj;
begin
 tobSource := TTestObj.Create;
 tobDest := TTestObj.Create;
 tobSource.AValue := 'Testing...';
 tobDest.Assign(tobSource);
 //Move(tobSource, tobDest, SizeOf(tobDest));
 ShowMessage('This value will display fine: ' + tobDest.AValue);
 tobSource.Free;
 ShowMessage('Even though the tobDest variable has not been released, this '
+
  'line results in an exception: ' + tobDest.AValue);
end;

end.

Re:Copying an object with Move raises an exception


Dan,

Quote
>Given the errors I was getting, I thought that Move must be doing a pointer
>copy.  Your'e right, what I want is the equivalent of Assign.  I tried to
>use it and while it's not available on TObject, it is available on
>TPersistent so I changed the class of TTestObj.  The problem is when I use
>assign, I get an EConverError exception 'Cannot assign a TTestObj to a
>TTestObj.'  This is what happens when I run the code sample shown below.

Take a look at the VCL source for TPersistent: the Assign method calls the
protected AssignTo method, which always raises an exception. You have to
override the AssignTo method in your descendant class, because there is no
way that Delphi can determine which variables and/or properties have to be
copied. You have to implement that yourself. Again, in the VCL sources, you
can find many examples of how you should do this, by looking at the AssignTo
method of any descendant of TPersistent.
Example:

procedure TCustomImageList.AssignTo(Dest: TPersistent);
var
  ImageList: TCustomImageList;
begin
  if Dest is TCustomImageList then
  begin
    ImageList := TCustomImageList(Dest);
    ImageList.Masked := Masked;
    ImageList.ImageType := ImageType;
    ImageList.DrawingStyle := DrawingStyle;
    ImageList.ShareImages := ShareImages;
    ImageList.BlendColor := BlendColor;
    with ImageList do
    begin
      Clear;
      SetNewDimensions(Self.Handle);
      if not HandleAllocated then HandleNeeded
      else ImageList_SetIconSize(Handle, Width, Height);
      BkColor := GetColor(ImageList_GetBkColor(Self.Handle));
      AddImages(Self);
    end;
  end
  else inherited AssignTo(Dest);
end;

HTH,

        Niels.

--------------------------------------------
Niels Vanspauwen
Student @ KULeuven
Faculty of Engineering
Department of Computer Science
--------------------------------------------
Author of the most powerful macro-component for all your
Delphi-applications.
TMagicMacros records, plays, shows infoboxes, supports VisualHelp, and much
more!
Check out: http://magicmacros.8m.com

Re:Copying an object with Move raises an exception


Ing. Franz Glaser heeft geschreven in bericht
<368561A8.640A6...@eunet.at>...
Quote
|Dan Richardson wrote:

|>
|> I have been attempting to copy an object with the move command.  This
works
|> until the variable used as the source in the move statement is released.
|> This causes the destination variable to be corrupted. To me this defies
the
|> idea of a copy.  I am enclosing sample code.

[large snip]

|I really do not understand which devil was riding those Delphi inventors
|to hide the pointer properties of pointers. It makes soooo much troubles
|and it has soooo little benefit to save a few keystrokes to enter the ^.
|
|It does not help, you have to learn Pascal earlier or later, if you
|want to understand the silly behaviour of Delphi.

{$DEFINE DISAGREE}
-Let's put things in the right context. Move() is a _generic_ , non-OOP
procedure that will move TAnything to anywhere, provided the right
information was supplied.

-Move(tobSource, tobDest, SizeOf(tobDest)); will indeed only copy 4 bytes
of data from tobSource to tobDest, since SizeOf(aPointer) always = 4.

-Move(tobSource, tobDest, SizeOf(TTESTOBJ)) however, will copy the whole
object.
( and will afterwards cause other problems, but that's another story)

-Note also that in the original code, tobDest was not CREATED, so tobDest
is pointing to NoWhere land.

-I certainly would not like Delphi to 'automatically' fill in the size
information.
  ( Move(p1, p2) ) ; what if I only wanted to copy part of something??

{$UNDEF DISAGREE}  :0)

Regards & Season's Greetings,
Dirk Claessens
______________________________________________
dirk.claess...@village.ZZuunet.be
dirk.claessens...@belgium.ZZagfa.com
Mailheader was forged  to fight spam !
Use the above and remove ZZ
______________________________________________

Re:Copying an object with Move raises an exception


Quote
Dirk Claessens wrote:

> Ing. Franz Glaser heeft geschreven in bericht
> |I really do not understand which devil was riding those Delphi inventors
> |to hide the pointer properties of pointers. It makes soooo much troubles
> |and it has soooo little benefit to save a few keystrokes to enter the ^.
> |
> |It does not help, you have to learn Pascal earlier or later, if you
> |want to understand the silly behaviour of Delphi.

> {$DEFINE DISAGREE}
> -Let's put things in the right context. Move() is a _generic_ , non-OOP
> procedure that will move TAnything to anywhere, provided the right
> information was supplied.

Exactly this is what I doubt. To find out _what_ is the right
information,
in this case: parameter, is not visible with the silly $X+ switch and
all
the related nonsense.
---
Quote
> -I certainly would not like Delphi to 'automatically' fill in the size
> information.
>   ( Move(p1, p2) ) ; what if I only wanted to copy part of something??

So do I. It would be an additional nonsense of the same kind.

The original poster Dan had good knowledge about Pascal and correct
usage of pointers, so it was easy to explain him the Delphi related
oddities in a direct mail.

Of course I know which devil was riding the inventors of Delphi!
The $X+ approach is obviously a commercial decision, to hide the
necessary pointer behaviour for the {*word*76}y beginners and VB upgraders.
Borland gives them the feeling of being able to handle the indeed
complicated world of OOPs easily. But this works only as long as they
create very simple application programs. With real programs it leads
to the well known mass of "Dr.Watson - loader" utilities.

Franz Glaser

Re:Copying an object with Move raises an exception


Ing. Franz Glaser heeft geschreven in bericht
<36863C75.3352D...@eunet.at>...

[snip]

|> -Let's put things in the right context. Move() is a _generic_ , non-OOP
|> procedure that will move TAnything to anywhere, provided the right
|> information was supplied.
|
|Exactly this is what I doubt. To find out _what_ is the right
|information,
|in this case: parameter, is not visible with the silly $X+ switch and
|all
|the related nonsense.
|---

Silly $X+ switch ?? from OnLine Help :
---
Note: The $X directive is provided for backwards compatibility with
previous versions of Borland Pascal. You should not use the {$X-} mode when
writing Delphi applications.
---
The default value is $X+ ; so what's the problem ??

|> -I certainly would not like Delphi to 'automatically' fill in the size
|> information.
|>   ( Move(p1, p2) ) ; what if I only wanted to copy part of something??

So do I. It would be an additional nonsense of the same kind.

I don't understand why you insist on calling it nonsense. It is clearly
documented by Inprise that Move() is a very fast but dangerous bulldozer.
The compiler translates it directly into an asssembler  mov x,y
instruction without asking questions, so you need to know what you're doing
or you'll end up in AV-country.

[snip]

|Of course I know which devil was riding the inventors of Delphi!
|The $X+ approach is obviously a commercial decision, to hide the
|necessary pointer behaviour for the {*word*76}y beginners and VB upgraders.
|Borland gives them the feeling of being able to handle the indeed
|complicated world of OOPs easily. But this works only as long as they
|create very simple application programs. With real programs it leads
|to the well known mass of "Dr.Watson - loader" utilities.

Sure. Making the user interface is easy, and then it suddenly stops. Code
needs to be written, and things must be understood. I'm not a VB-fan at
all, but do you know why VB is so popular? Simply because MS has shielded
off the messy details, in order to make it _easy_ to build "real" apps. The
beauty - and the strenght - of Delphi is that you can choose the level of
"power" you wish to use. You can have it the VB-way ( simply grabbing
components of the palette, connect them, and write a little code ), or the
more elaborate way, by developing new components, etc..

Maybe Inprise should provide for some kind of "Level" option in D5.  ( you
know : Easy/Advanced/Professional ) That way, the "dangerous" parts of the
OOP-environment could be hided from the user...

Regards,
Dirk Claessens
______________________________________________
dirk.claess...@village.ZZuunet.be
dirk.claessens...@belgium.ZZagfa.com
Mailheader was forged  to fight spam !
Use the above and remove ZZ
______________________________________________

Re:Copying an object with Move raises an exception


Quote
Dirk Claessens wrote:
> Maybe Inprise should provide for some kind of "Level" option in D5.  ( you
> know : Easy/Advanced/Professional ) That way, the "dangerous" parts of the
> OOP-environment could be hided from the user...

Agreed, like with chess programs :-)

But then I would really like to see the used level on top of the
"about" dialog window, or even more important, on the CD cover...

Franz Glaser

Other Threads