До сих пор вы получили много хороших ответов, но, начиная с ответа, что вы уже имеете дело с указателями, когда используете длинные строки, динамические массивы и ссылки на объекты, вы должны задуматься, почему вы сделали бы использовать указатели вместо длинных строк, динамических массивов и ссылок на объекты. Есть ли причина по-прежнему использовать указатели, учитывая, что во многих случаях Delphi хорошо скрывает их от вас?
Позвольте мне привести два примера использования указателя в Delphi. Вы увидите, что это, вероятно, совсем не относится к вам, если вы в основном пишете бизнес-приложения. Однако это может стать важным, если вам когда-либо понадобится использовать функции API Windows или сторонних производителей, которые не импортированы ни одним из стандартных модулей Delphi, и для которых не найдены модули импорта (например, в библиотеках JEDI). И это может быть ключом для достижения необходимого последнего бита скорости в коде обработки строк.
Указатели могут использоваться для работы с типами данных различных размеров (неизвестно во время компиляции)
Рассмотрим тип данных растрового изображения Windows. Каждое изображение может иметь различную ширину и высоту, и существуют различные форматы, начиная от черно-белого (1 бит на пиксель) и заканчивая 2 ^ 4, 2 ^ 8, 2 ^ 16, 2 ^ 24 или даже 2 ^ 32 серыми значениями или цветами , Это означает, что во время компиляции неизвестно, сколько памяти займет растровое изображение.
В windows.pas есть тип TBitmapInfo :
type
PBitmapInfo = ^TBitmapInfo;
tagBITMAPINFO = packed record
bmiHeader: TBitmapInfoHeader;
bmiColors: array[0..0] of TRGBQuad;
end;
TBitmapInfo = tagBITMAPINFO;
Элемент TRGBQuad описывает один пиксель, но растровое изображение, конечно, содержит более одного пикселя. Поэтому никогда не следует использовать локальную переменную типа TBitmapInfo , но всегда указатель на нее:
var
BmpInfo: PBitmapInfo;
begin
// some other code determines width and height...
...
BmpInfo := AllocMem(SizeOf(TBitmapInfoHeader)
+ BmpWidth * BmpHeight * SizeOf(TRGBQuad));
...
end;
Теперь с помощью указателя вы можете получить доступ ко всем пикселям, хотя TBitmapInfo имеет только один. Обратите внимание, что для такого кода вы должны отключить проверку диапазона.
Подобные вещи, конечно, можно обрабатывать и с классом TMemoryStream , который по сути является дружественной оболочкой для указателя на блок памяти.
И, конечно, гораздо проще просто создать TBitmap и назначить его ширину, высоту и формат пикселей. Чтобы заявить это снова, Delphi VCL устраняет большинство случаев, когда в противном случае понадобились бы указатели.
Указатели на символы могут использоваться для ускорения строковых операций
Это, как и большинство микрооптимизаций, что-то, что нужно использовать только в крайних случаях, после того, как вы профилировали и нашли код, использующий строки, которые занимают много времени.
Хорошим свойством строк является то, что они подсчитываются ссылками. Копирование их не копирует занимаемую ими память, а только увеличивает счетчик ссылок. Только когда код попытается изменить строку, у которой счетчик ссылок больше 1, будет скопирована память, чтобы создать строку с счетчиком ссылок 1, которую затем можно безопасно изменить.
Не очень приятным свойством строк является то, что они подсчитываются ссылками. Каждая операция, которая может изменить строку, должна убедиться, что счетчик ссылок равен 1, потому что в противном случае изменение строки будет опасным. Замена символа в строке является такой модификацией. Чтобы убедиться, что счетчик ссылок равен 1, компилятор добавляет вызов UniqueString () всякий раз, когда записывается символ в строке. Теперь запись n символов строки в цикле приведет к вызову UniqueString () n раз, даже если после первого раза гарантируется, что количество ссылок равно 1. Это означает, что в основном n - 1 вызовы UniqueString () выполняются без необходимости.
Использование указателя на символы является распространенным способом ускорения строковых операций, в которых используются циклы. Представьте, что вы хотите (для целей отображения) заменить все пробелы в строке маленькой точкой. Используйте представление CPU отладчика и сравните код, выполненный для этого кода
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;
с этим кодом
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;
Во второй функции будет только один вызов UniqueString () , когда адрес первого символа строки назначен указателю на символ.