У меня есть много выделений памяти и то же количество вызовов FreeMem. Что я не имел, хотя проверка перед звонящими почетными гражданами, чтобы видеть, был ли указатель нолем и строкой после освобождения для установки указателя на ноль.
Я пытался создать функцию, чтобы сделать это
procedure FreeMemAndNil(p: Pointer; size: Integer = -1);
begin
if p <> nil then
begin
if size > -1 then
FreeMem(p, size)
else
FreeMem(p);
p := nil;
end;
end;
Но существует проблема. Это не может установить origional указатель на ноль, потому что параметр не является переменным (var p: Указатель). Я не могу использовать var, хотя, потому что, если я, компилятор жалуется, тип должен быть тем же самым типом (Указатель). Указатели я являюсь передающим, могли быть указателями на любой тип (PChar, регулярный указатель, и т.д.).
Что я могу сделать для фиксации этого? Существует ли лучшее решение?
Подобно Мейсон Уиллер сказал, что вы должны использовать тот же трюк, что и FreeAndNil в модуле SysUtils для ссылок на объекты.
Итак, я изменил ваш код, проверил его, и он отлично работает:
procedure FreeMemAndNil(var ptr; size: Integer = -1);
var
p: Pointer;
begin
p := Pointer(ptr);
if p <> nil then
begin
if size > -1 then
FreeMem(p, size)
else
FreeMem(p);
Pointer(ptr) := nil;
end;
end;
- jeroen
PS: Роб Кеннеди написал хороший ответ на нетипизированные параметры var , в котором есть ссылка на его нетипизированный параметр страница в Интернете.
PS2: Для справки: Kylix-версия SysUtils.pas находится в интерактивном режиме , а FreeAndNil там идентичен тому, как он находится в Delphi.
В SysUtils есть процедура под названием FreeAndNil, которая делает это для объектов. Он делает это с помощью нетипизированного параметра var , который он преобразует в TObject, и вы должны убедиться, что вы не передали ему что-то, кроме TObject. Вы можете сделать что-то подобное здесь, если вам нужно. Просто будь осторожен; если вы это сделаете, безопасности типов не будет.
Я часто работаю с ReallocMem для работы с указателями/памятью.
Вызов
ReallocMem(P,0)
установит указатель в Nil.
1 вещь, которую вам нужно знать об использовании этой функции, P должен быть инициализирован перед передачей в ReallocMem.
.Чтобы иметь возможность передавать произвольные значения указателя в эту функцию, вам необходимо следовать той же модели, что и FreeAndNil, и передавать нетипизированный параметр . В противном случае компилятор правильно жалуется на несовпадение фактических и формальных типов параметров. Приведите нетипизированный параметр к Pointer, когда вы вызываете для него FreeMem.
В этой функции вы делаете пару бессмысленных вещей.
Прежде всего, освобождение нулевого указателя всегда безопасно, поэтому нет причин проверять это перед вызовом FreeMem. Это освобождает указатель, отличный от nil, о котором вам нужно беспокоиться, но никакая функция не защитит вас от этого.
Далее, параметр размера FreeMem в течение многих лет игнорировался. Раньше считалось, что если вы предоставляли этот параметр, он должен был соответствовать размеру, переданному в GetMem, но в настоящее время FreeMem полностью игнорирует этот параметр - компилятор даже не передает этот параметр функции.
Учитывая все вышесказанное, ваша функция сводится к следующему:
procedure FreeMemAndNil(var P);
var
Tmp: Pointer;
begin
Tmp := Pointer(P);
Pointer(P) := nil;
FreeMem(Tmp);
end;
Будьте осторожны, чтобы случайно не вызвать эту функцию для всего, что не указатель, выделенный с помощью GetMem. Компилятор не поймает это за вас, как если бы вы использовали типизированные параметры. Если вы попытаетесь освободить что-то, что не было выделено с помощью GetMem, вы, вероятно, получите исключение EInvalidPointer, но переменная, которую вы передали, после этого все равно будет равна нулю. Таким же образом работает FreeAndNil.