PDA

View Full Version : Pointers :P



Gadget
26-01-2003, 09:13 PM
Couple of quick questions about pointers as they always drive me nuts in Delphi, especially when doing more complex stuff.

1) I have this simple routine for extracting previously decompressed images that I store in TBitmaps. The function returns type TBitmap.
FaPBitmap is an array of ^TBitmap

function ExtractImage(Index: Integer): TBitmap;
begin
Result := FaPBitmap[Index]^;
end;

The problem I have is when I use a TBitmap variable in the calling routines of this function to hold the result, when I destroy the temporary bitmap after I have finished copying it to a DX surface, the orginial is destroyed. This is because I passed back a pointer to the original! How can I get around this? I want to pass the actuall thing itself as a 'new' entity for the calling procedure to destroy once done. At the moment I can display each image once lol...

2) How can you increment a pointer by x number of bytes? Inc(myPointer) works, but how can I add say 256 for instance?

Clootie
26-01-2003, 11:48 PM
1) Create new bitmap and use AssignTo to copy content of original bitmal?
2) Incrementing a pointer by x number of bytes: [background=#FFFFFF][normal=#000000][number=#0000FF][string=#0000FF][comment=#248F24][reserved=#000000]// If pointer is PByte then:
Inc(p, 256);
// else
p:= Pointer(Cardinal(p) + 256);

Stevie56
29-01-2003, 12:31 AM
When doing this I would write.....

function ExtractImage(Index: Integer): TBitmap;
begin
Result:=TBitmap.Create; // create a bitmap for the return
Result.assign(FaPBitmap[Index]^);
end;


Hope this helps a little.

Gadget
29-01-2003, 08:49 AM
When doing this I would write.....

function ExtractImage(Index: Integer): TBitmap;
begin
Result:=TBitmap.Create; // create a bitmap for the return
Result.assign(FaPBitmap[Index]^);
end;


Hope this helps a little.

Hi, that's exactly what I ended up doing :)

Thanks! And thanks Clootie :)

Alimonster
30-01-2003, 09:44 AM
Are you absolutely, positively sure that you need a ^TBitmap (a pointer to a pointer, in other words). IME it's pretty rare to require pointers to classes, especially since Delphi has var parameters in functions.

Just making sure, that's all...

Gadget
03-05-2003, 11:00 AM
Are you absolutely, positively sure that you need a ^TBitmap (a pointer to a pointer, in other words). IME it's pretty rare to require pointers to classes, especially since Delphi has var parameters in functions.

Just making sure, that's all...

Not entirely sure what you mean... I ended up just passing back the pointer to the TBitmap, this allows me to blit the bitmap to a DX surface, without creating a new TBitmap object first. Seems very fast, is there a faster more recommended way of drawing in tile based games? It seems effective to extract my bitmaps, store in a large array and pass pointers to the paint routine as and when required?

Sorry for the long wait in my reply btw... I am trying to code the entire game myself (MMORPG), which is taking a lot of time and energy.

TheLion
03-05-2003, 11:07 AM
What he means is that an object in Delphi allready is a pointer. Another method you might consider (and might even be faster) is using a TList and simply adding the TBitmap objects to it. A TList is way faster than an array and the principle is the same! :)

Alimonster
05-05-2003, 10:38 AM
TheLion got my meaning there. I'll expand on my previous post.

All classes are implicit pointers. This means that you can change an object without requiring var parameters. E.g.

[background=#FFFFFF][comment=#0000FF][normal=#000000][number=#C00000][reserved=#000000][string=#00C000]type
TWhatever = class
private
FValue: Integer;
public
property Value: Integer read FValue write FValue;
end;

procedure ChangeMe(xyz: TWhatever);
begin
xyz.Value := 321;
end;

procedure Test;
var
Blah: TWhatever;
begin
Blah := TWhatever.Create;
Blah.Value := 123;
ShowMessage('The value of blah is ' + IntToStr(Blah.Value));

ChangeMe(Blah);
ShowMessage('The value is now ' + IntToStr(Blah.Value));
Blah.Free;
end;
Notice how the above changes the value of blah. If you expected it to be copied-by-value then your intuition ain't right. Notice, though, that this behaviour is the same as the pointer.

Next, consider the size of a class:

[background=#FFFFFF][comment=#0000FF][normal=#000000][number=#C00000][reserved=#000000][string=#00C000]procedure Example2;
begin
if SizeOf(TWhatever) = SizeOf(Pointer) then
ShowMessage('Now that''s interesting...')
else
ShowMessage('This never gets shown');
end;

A class instance will be four bytes in size - it's a pointer.

Classes are pointers, which means that it's very uncommon to require pointer-to-classes (like your ^TBitmap). You can allocate memory for your classes, initialise it to zero, and call relevant constructors when you create the class. Once that's done, your class will have memory associated with it (which is why you need to free it).

Passing classes in the standard fashion ("procedure Whatever(Someclass: TSomething)") lets you change the class's fields, but not the area of memory to which it's assigned. The only time you'd want to pass a pointer to the class would be if you wanted to point the object to somewhere else.

Remember how I said before that classes point to a chunk of memory? Maybe we would want to point it somewhere else. How about the following, where we have two allocated buttons (maybe sitting on a form) and one that's a reference (no memory allocated, just pointing to one of the buttons for some reason):

[background=#FFFFFF][comment=#0000FF][normal=#000000][number=#C00000][reserved=#000000][string=#00C000]procedure TForm1.ChangeMe(var AButton: TButton);
begin
AButton := Button2;
end;

procedure TForm1.Blah;
var
Temp: TButton;
begin
Temp := Button1; // point to the first button

// do something else

ChangeMe(Temp);

// temp will point to the second button now
end;

Notice the change in behaviour here -- we want to change the area of memory to which our class instance points. Therefore, we have to pass in a var parameter for ChangeMe -- if we don't then copy by value will take place and our button won't point to somewhere else and the reference will still point to the first button instead of the second. You can also use a pointer-to-TButton here in the ChangeMe procedure but I'd recommend against it.

So, in short, you only want to use a pointer-to-class if you want to change the area of memory that an object points to. It's not more efficient to use pointers-to-classes since classes are already pointers -- in fact, it may be slightly less efficient since you have to dereference them twice.

Now, thinking about the above, it should be clear why I said something like "they're pretty rare, especially because of var params" (paraphrasing myself). In short, if you need to change a object's fields, you can just pass it in as normal. If you want to point the object to somewhere else (being careful to .free it if you .created it, of course), then you can pass the object as var parameter (but without using a pointer to it).

Of course, you may have a reason to use ^TBitmaps instead of TBitmaps + var parameters where necessary. My intuition says that this isn't too likely, though.