Свободная память и ноль в Delphi с использованием одной функции
У меня много выделений памяти и такое же количество вызовов FreeMem. Однако у меня не было проверки перед вызовом 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;
но есть проблема. Он не может установить исходный указатель на ноль, потому что параметр не является переменным (var p: Pointer). Я не могу использовать var, потому что если я это сделаю, компилятор жалуется тип должен быть точно таким же типом (указатель). Указатели я передаю могут быть указателями на любой тип (PChar, обычный указатель, и т. д.).
что я могу сделать, чтобы это исправить? Есть ли лучшее решение?
4 ответов
Как Мейсон Уилер сказал, что вы должны использовать тот же трюк, что 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 on-line, и FreeAndNil там идентичен тому, как он находится в Delphi.
чтобы иметь возможность передавать произвольные значения указателя этой функции, вам нужно следовать той же модели, что и FreeAndNil, и передать нетипизированный параметр. В противном случае компилятор правильно жалуется на то, что фактические и формальные типы параметров не идентичны. Type-приведите нетипизированный параметр к указателю при вызове FreeMem.
Вы делаете пару бессмысленных вещей в этой функции.
прежде всего, освобождение нулевого указателя всегда безопасно, поэтому нет причин проверять это, прежде чем звонить FreeMem. Это освобождение указателя без нуля, о котором вам нужно беспокоиться, но никакая функция не может защитить вас от этого.
далее, параметр размера для FreeMem игнорируется в течение многих лет. Раньше, если вы предоставили этот параметр, он должен был соответствовать размеру, переданному GetMem, но в настоящее время FreeMem полностью игнорирует этот параметр - компилятор даже не передает этот параметр функции.
С все вышесказанное в виду, ваша функция сводится к этому:
procedure FreeMemAndNil(var P);
var
Tmp: Pointer;
begin
Tmp := Pointer(P);
Pointer(P) := nil;
FreeMem(Tmp);
end;
будьте осторожны, чтобы случайно не вызывать эту функцию на что-нибудь, что не указатель, выделенный GetMem. Компилятор не поймает его для вас, как если бы вы использовали типизированные параметры. Если вы попытаетесь освободить что-то, что не было выделено GetMem, вы, вероятно, получите исключение EInvalidPointer, но переменная, которую вы передали, все равно будет равна нулю. То же самое. FreeAndNil работает.
в SysUtils есть процедура FreeAndNil, которая делает это для объектов. Он делает это с помощью нетипизированного var параметр, который он бросает в TObject, и это зависит от вас, чтобы убедиться, что вы не передаете ему что-то, что не является TObject. Вы могли бы сделать что-то подобное здесь, Если тебе нужно. Просто будь осторожен; если ты сделаешь это, не будет никакой безопасности.
Я, как правило, много работаю с ReallocMem для работы с указателем / памятью.
вызов
ReallocMem(P,0)
установит указатель на ноль.
1 что вам нужно знать об использовании его, P необходимо инициализировать перед передачей в ReallocMem.