Using Pointers in Delphi

I’ve been developing for some time, and so far I have not used pointers in my development.

So what are the benefits of pointers? Does the application run faster or use less resources?

Since I am sure that pointers are important, can you "point" me to some articles, basic, but it’s good to start using pointers in Delphi? Google gives me too much, too special results.

+6
pointers delphi
source share
4 answers

A pointer is a variable that points to a portion of memory. Benefits:

  • you can specify the part of memory that you want.
  • you only need to change the pointer to point to another piece of memory that saves a lot of time on copying.

Delphi uses many hidden pointers. For example, if you use:

var myClass : TMyClass; begin myClass := TMyClass.Create; 

myClass is a pointer to an object.

Another example is a dynamic array. This is also a pointer.

To learn more about pointers, you need to learn more about memory. Each piece of data can exist in different pieces of data.

For example, global variables:

 unit X; interface var MyVar: Integer; 

A global variable is defined in the data array. The data commit is fixed. And throughout the life of the program, these variables are available. This means that memory cannot be used for other purposes.

Local variables:

 procedure Test; var MyVar: Integer; 

A local variable exists on the stack. This is the part of the memory that is used for the household. It contains the parameters for the function (ok some are put into the register, but this is not important now). It contains a return address, so the CPU knows where to return if the program has ended. And it contains local variables used in functions. Local variables exist only during the life of a function. If the function is completed, you cannot access the local variable in a reliable way.

Heap Variables:

 procedure Test2; var MyClass: TMyClass; begin MyClass := TMyClass.Create; 

The variable MyClass is a pointer (a local variable that is defined on the stack). By building an object, you allocate a piece of memory in a heap (most of the "other" memory that is not used for programs and stacks). The MyClass variable contains the address of this piece of memory. Heap variables exist until you release them. This means that if you exit Test2 without freeing the object, the object still exists on the heap. But you will not be able to access it, because the address (MyClass variable) is missing.

Recommendations

It is almost always advisable to allocate and free a pointer variable at the same level.

For example:

 var myClass: TMyClass; begin myClass := TMyClass.Create; try DoSomething(myClass); DoSomeOtherthing(myClass); finally myClass.Free; end; end; 

If you can, try to avoid functions that return an instance of the object. There is never any certainty that the caller must dispose of the facility. And this creates memory leaks or crashes.

+30
source share

You have been given a lot of good answers at the moment, but starting with the answer that you are already dealing with pointers when using long strings, dynamic arrays and object references, you should start to wonder why you would use pointers instead of long strings, dynamic arrays and object references. Is there a reason to still use pointers, given that Delphi does a good job of hiding them from you in many cases?

Let me give you two examples of using a pointer in Delphi. You will see that this is probably not at all suitable for you if you are mostly writing business applications. However, it can become important if you ever need to use functions of Windows or third-party APIs that are not imported by any of the standard Delphi modules, and for which there are no import units in (for example) JEDI libraries. And that may be the key to achieving the required speed bit in the string processing code.

Pointers can be used to process data types of various sizes (unknown at compile time)

Consider the Windows bitmap data type. Each image can have a different width and height, and there are different formats: from black and white (1 bit per pixel) from 2 ^ 4, 2 ^ 8, 2 ^ 16, 2 ^ 24, or even from 2 ^ 32 gray values ​​or colors , This means that at compile time it is not known how much memory the bitmap will take.

In windows.pas, there is a type of TBitmapInfo:

 type PBitmapInfo = ^TBitmapInfo; tagBITMAPINFO = packed record bmiHeader: TBitmapInfoHeader; bmiColors: array[0..0] of TRGBQuad; end; TBitmapInfo = tagBITMAPINFO; 

The TRGBQuad element describes one pixel, but the bitmap, of course, contains more than one pixel. Therefore, you should never use a local variable of type TBitmapInfo, but always a pointer to it:

 var BmpInfo: PBitmapInfo; begin // some other code determines width and height... ... BmpInfo := AllocMem(SizeOf(TBitmapInfoHeader) + BmpWidth * BmpHeight * SizeOf(TRGBQuad)); ... end; 

Now, using a pointer, you can access all the pixels, although TBitmapInfo has only one. Please note that for such code you must disable range checking.

Of course, the same material can be used with the TMemoryStream class, which is basically a friendly wrapper around a pointer to a memory block.

And of course, it’s much easier to just create a TBitmap and assign its width, height, and pixel format. To point it again, Delphi VCL eliminates most cases where pointers would otherwise be needed.

Character pointers can be used to speed up string operations.

This, like most micro optimizations, can only be used in extreme cases, after you have profiled and found the code using strings to consume a lot of time.

A good property of strings is that they are counted by reference. Copying them does not copy the memory that they occupy, it only increases the reference counter. Only when the code tries to change a line that has a reference count greater than 1 will memory be copied to create a line with reference number 1, which can then be safely changed.

The uncommon property of strings is that they are counted by reference. Each operation that can change a string must ensure that the reference count is 1, because otherwise modifying the string would be dangerous. Replacing a character in a string is such a modification. To ensure that the reference count is 1, a call to UniqueString () is added by the compiler whenever a character is written in a string. Now writing n characters of a line in a loop will cause UniqueString () to be called n times, even if after the first time it is ensured that the reference count is 1. This means that basically n - 1 calls to UniqueString () are made unnecessarily.

Using a character pointer is a common way to speed up operations on strings that are associated with loops. Imagine that you want (to display) replace all spaces in a line with a small dot. Use the processor view for the debugger and compare the code executed for this code.

 procedure MakeSpacesVisible(const AValue: AnsiString): AnsiString; var i: integer; begin Result := AValue; for i := 1 to Length(Result) do begin if Result[i] = ' ' then Result[i] := $B7; end; end; 

with this code

 procedure MakeSpacesVisible(const AValue: AnsiString): AnsiString; var P: PAnsiChar; begin Result := AValue; P := PAnsiChar(Result); while P[0] <> #0 do begin if P[0] = ' ' then P[0] := $B7; Inc(P); end; end; 

The second function will only have one call to UniqueString () when the address of the first character of the string is assigned to the char pointer.

+10
source share

You probably used pointers, but you just don't know that. A class variable is a pointer, a string is a pointer, a dynamic array is a pointer, Delphi just hides it for you. You will see them when you make API calls (string casting on PChar), but even then Delphi can hide a lot.

See Gamecats answer for the benefits of pointers.

In this About.com article, you can find a basic explanation of pointers in Delphi.

+2
source share

Pointers are needed for some data structures. The simplest example is a linked list. The advantage of such structures is that you can recombine elements without moving them in memory. For example, you might have a linked list of large complex objects and swap any two of them very quickly, because you really need to set up two pointers instead of moving these objects.

This applies to many languages, including Object Pascal (Delphi).

+2
source share

All Articles