Программер просит у друга денег в долг:
- Одолжи 250$ до получки, ну или для ровного счета 256?
Я создал простой модуль и разработал несколько простых методов, помогающих избежать использования неактуальных (в оригинале было "stale" - черствый, несвежий) указателей. Я настоятельно рекомендую добавить во все модули, содержащие указатели или объектные переменные секцию инициализации ('initialization') и установить все указатели (объектные переменные это те же реальные указатели) в nil. Что это даст: прежде чем хотя бы один указатель будет использован, он обязательно будет проверен, освобожден и установлен в nil. Затем, после освобождения указателей, просто установите их в nil. Мой модуль содержит функцию Nilify() для установки указателей в nil, а также специальные версии методов Free, Dispose, и FreeMem (названные NilXXX) для проверки значения nil перед освобождением памяти, и установления указателя в nil сразу после того, как он был освобожден. Я также включил специальную версию Assigned(), названную IsNil(), которая вместо переменного (var) параметра получает константу, которую вы можете затем использовать в своих свойствах, и т.п.
Этот модуль, конечно, ничего не делает с VCL, но тем не менее вы можете иметь неактуальные указатели и с VCL... Строгое соблюдение функций модуля сделает вас уверенным в отсутствии ошибок при работе с указателями. Единственное условие использования модуля - в случае любых изменений кода с вашей стороны или наличия каких-либо замечаний или предложений пришлите их пожалуйста мне. Пользуйтесь на здоровье!
unit Pointers;
{
Автор: David S. Becker (dsb@plaza.ds.adp.com)
Дата: 1/27/97
Авторские права: Нет
Дистрибутивные права: Свободные, неограниченное использование, в случае любых изменений кода
с вашей стороны или наличия каких-либо замечаний или предложений пришлите их пожалуйста мне.
Данный модуль создавался для помощи в управлении указателями и объектами. Так как
компилятор не инициализирует указатели и объекты в nil и не сбрасывает
их в nil при освобождении, существует вероятность применения неактуального
указателя. По этой причине я рекомендую добавление секции 'initialization'
во все модули и вызове Nilify() для всех указателей/объектов в данном модуле.
Это позволит быть уверенным, что все указатели/объекты стартуют как nil.
Кроме того, вместо стандартных аналогов, вы можете использовать NilFree
(для объектов), NilDispose (для указателей, создаваемых с помощью New),
и NilFreeMem (для указателей, создаваемых с помощью GetMem). Эти процедуры
безопасны при вызове nil-вых указателей/объектов, так как перед выполнением
любых действий они проверяют их на nil. После освобождения распределенной
указателем/объектом памяти они сбрасываются в nil. Строгое соблюдение функций
модуля значительно снижает риск использования неактуального указателя.
(Конечно, вы еще можете получить неактуальные указатели из VCL, т.к.
они, естественно, не используют данные функции.)
}{==============================================================================}interface{------------------------------------------------------------------------------}{ Проверка указателя на nil }{ ПРИМЕЧАНИЕ: Данная функция отличается от Assigned() тем, что Assigned() }{ требует переменную, а IsNil() нет. }function IsNil(const p: Pointer): Boolean;
{ Устанавливает указатель в nil }procedure Nilify(var p);
{ Освобождает не-nil объект и устанавливает его в nil }procedure NilFree(o: TObject);
{ Освобождает не-nil указатель, созданный с помощью New и устанавливает его в nil }procedure NilDispose(var p: Pointer);
{ Освобождает не-nil указатель и устанавливает его в nil }procedure NilFreeMem(var p: Pointer; size: Word);
{==============================================================================}implementation{------------------------------------------------------------------------------}function IsNil(const p: Pointer): Boolean;
begin
Result := (p = nil);
end;
{------------------------------------------------------------------------------}procedure Nilify(var p);
begin
Pointer(p) := nil;
end;
{------------------------------------------------------------------------------}procedure NilFree(o: TObject);
beginifnot IsNil(o) thenbegin
o.Free;
Nilify(o);
end;
end;
{------------------------------------------------------------------------------}procedure NilDispose(var p: Pointer);
beginifnot IsNil(p) thenbegin
Dispose(p);
Nilify(p);
end;
end;
{------------------------------------------------------------------------------}procedure NilFreeMem(var p: Pointer; size: Word);
beginifnot IsNil(p) thenbegin
FreeMem(p, size);
Nilify(p);
end;
end;
end.
Статья Как избежать использования неактуальных указателей раздела Синтаксис Память и Указатели может быть полезна для разработчиков на Delphi и FreePascal.
Комментарии и вопросы
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.