Se le ha dado un montón de buenas respuestas hasta el momento, pero a partir de la respuesta que ya se está ocupando de los punteros cuando se utiliza cadenas largas, matrices dinámicas y referencias a objetos usted debe comenzar a preguntarse por qué haría uso punteros, en lugar de cadenas largas, matrices dinámicas y referencias a objetos. ¿Hay alguna razón para seguir usando punteros, dado que Delphi hace un buen trabajo ocultándoselos, en muchos casos?
Permítame darle dos ejemplos del uso del puntero en Delphi. Verá que probablemente esto no sea relevante para usted si escribe principalmente aplicaciones comerciales. Sin embargo, puede volverse importante si alguna vez necesita usar Windows o funciones de API de terceros que no son importadas por ninguna de las unidades Delphi estándar, y para las cuales no se pueden encontrar unidades de importación en (por ejemplo) las bibliotecas JEDI. Y puede ser la clave para lograr ese último bit de velocidad necesario en el código de procesamiento de cadenas.
punteros se pueden utilizar para hacer frente a los tipos de datos de diferentes tamaños (desconocidos en tiempo de compilación)
considerar el tipo de datos de mapa de bits de Windows. Cada imagen puede tener diferentes anchos y alturas, y hay diferentes formatos que varían desde blanco y negro (1 bit por píxel) sobre 2^4, 2^8, 2^16, 2^24 o incluso 2^32 valores de gris o colores . Eso significa que no se sabe en tiempo de compilación cuánta memoria ocupará un mapa de bits.
En windows.pas existe la TBitmapInfo tipo:
type
PBitmapInfo = ^TBitmapInfo;
tagBITMAPINFO = packed record
bmiHeader: TBitmapInfoHeader;
bmiColors: array[0..0] of TRGBQuad;
end;
TBitmapInfo = tagBITMAPINFO;
El TRGBQuad elemento describe un solo píxel, pero el mapa de bits hace, por supuesto, contiene más de un píxel.Por lo tanto, uno nunca utilizar una variable local de tipo TBitmapInfo, pero siempre un puntero a ella:
var
BmpInfo: PBitmapInfo;
begin
// some other code determines width and height...
...
BmpInfo := AllocMem(SizeOf(TBitmapInfoHeader)
+ BmpWidth * BmpHeight * SizeOf(TRGBQuad));
...
end;
Ahora, utilizando el puntero se puede acceder a todos los píxeles, a pesar de que TBitmapInfo no solo tienen una sola. Tenga en cuenta que para dicho código, debe desactivar la comprobación de rango.
Por supuesto, este tipo de cosas también pueden manejarse con la clase 0emrystStream , que es básicamente un envoltorio amigable alrededor de un puntero a un bloque de memoria.
Y, por supuesto, es mucho más fácil crear unTBitmap y asignar su ancho, alto y formato de píxeles. Para decirlo de nuevo, Delphi VCL elimina la mayoría de los casos en los que de otro modo serían necesarios punteros.
punteros a caracteres se pueden utilizar para acelerar las operaciones de cadena
Esto es, como la mayoría de las optimizaciones micro, algo para ser utilizado sólo en casos extremos, después de haber perfilado y ha encontrado el código de uso de cadenas para consumir mucho tiempo.
Una buena propiedad de las cadenas es que son contadas por referencia. Copiarlos no copia la memoria que ocupan, sino que solo aumenta el recuento de referencias. Solo cuando el código intente modificar una cadena que tenga un recuento de referencia mayor que 1 se copiará la memoria, para crear una cadena con un recuento de referencia de 1, que luego se puede modificar de forma segura.
Una propiedad no tan agradable de strings es que son referencias contadas. Cada operación que posiblemente pueda modificar la cadena tiene que asegurarse de que el recuento de referencia sea 1, porque de lo contrario las modificaciones a la cadena serían peligrosas. Reemplazar un personaje en una cadena es una modificación. Para asegurarse de que el recuento de referencias sea 1, el compilador agrega una llamada a UniqueString() cuando se escribe un carácter en una cadena. Y así por escrito n caracteres de una cadena en un bucle causará UniqueString() ser llamado n veces, a pesar de que después de la primera vez que se está seguro de que la cuenta de referencia es 1. Esto significa básicamente n - 1 llamadas de UniqueString() se realizan innecesariamente.
Usar un puntero a los caracteres es una forma común de acelerar las operaciones de cadena que involucran bucles. Imagine que desea (para fines de visualización) reemplazar todos los espacios en una cadena con un pequeño punto. Utilice la vista de la CPU del depurador y comparar el código ejecutado para este código
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;
con este código
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;
En la segunda función habrá sólo una llamada a UniqueString(), cuando la dirección del primer carácter de cadena está asignada al puntero de char.
Espero que esto es suficiente información, puedo agregar más si lo desea. –
+1 Excelente explicación. ¡Buen trabajo! –
Gracias, me gusta ayudar. Pero siempre es bueno si se aprecia. –