Аналог FreeAndNil с проверкой типа

    Для борьбы с проблемой «висячих» ссылок на освобожденные объекты в Delphi обычно используется процедура SysUtils.FreeAndNil. Процедура FreeAndNil освобождает объект и устанавливает переменную в nil.
    Но мне всегда не нравилось то, что в этой процедуре не типизированный параметр. И туда можно передать не только объект, но и строку, число и любую переменную. Естественно при вызове с таким некорректным параметром будут проблемы. Что самое неприятное проблемы могут вылезти совсем в другом месте.
    Мне хотелось бы чтобы компилятор меня контролировал, желательно на этапе компиляции. Но увы найти решение при котором компилятор ругался на попытку вызвать процедуру освобождающую и обнуляющую, с параметром не совместимым с TObject мне не удалось. Зато я нашел метод при котором такая попытка обнаруживалась на этапе выполнения при первом вызове. В общем, лучше один раз увидеть. Вот код более безопасного аналога FreeAndNil.

    unit CommonUnit;
    interface
    type
      TObjectHelper = class helper for TObject
      public
        procedure Free(var Obj);
      end;
    implementation
    procedure TObjectHelper.Free(var Obj);
    begin
      Assert(Self = Pointer(Obj), 'TObjectHelper.FreeSelf wrong type');
      if Self <> nil then
      begin
        Pointer(Obj) := nil;
        Destroy;
      end;
    end;
    end.
     

    В параметре методу передается ссылка на переменную, которую надо обнулить. Предполагается, что это будет сам объект метод которого вызывается. Вот например так: Obj.Free(Obj);
    При подключении этого модуля компилятор заставит заменить все вызовы стандартного Free на новый Obj.Free(Obj). Что для меня оказалось удобным. Если полная замена стандартного Free не требуется, то можно поменять имя метода в TObjectHelper.
    В итоге получаем функционал аналогичный стандартному FreeAndNil в методе, который невозможно вызвать для других типов. Дополнительный контроль типа. И подсказки компилятора на места где остался стандартный Free. В минусах пусть будет несколько некрасивый вызов, необходимость два раза указывать имя переменной.
    Да, в новых версиях Delphi эту задачу возможно решить более красиво, но я был ограничен Delphi 2007.
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 19

      +1
      В XE4 обещают вроде как ARC — контроль количества ссылок на объекты и автоматическое освобождение объекта, когда он более не используется, а также слабые и сильные ссылки.
        +1
        Да, в новых версиях прогресс заметен. И там подобны хак уже не нужен.
        Но в данной задаче я был ограничен 11й версией. Фактически нужно было в уже готовом коде найти проблему с двойным дестроем. Вот именно идеей появившейся при решении этой конкретной задачи я и поделился.
          +4
          Повторный вызов деструктора вполне себе отлавливает FastMM.
          +2
          ARC только для iOS будет. ПОкрайней мере в XE4. Вроде как для андроид в будущих версиях планируют. Для десктопа же все очень туманно.
            0
            В такие минуты чувствуешь себя слоупоком, оказывается XE4 уже «зарелизили», на ру-борде появилась ссылка буквально пару часов назад.
          +2
          Простите, но я вообще не понимаю, как можно пытаться вызвать FreeAndNil для строки или числа. В голове не укладывается.
            –1
            Ну например так. Был TList потом заменили на массив а про FreeAndNil забыли. В общем, не важно как. Важно что в данном случае ничто не защищает от ошибки кроме внимательности программиста.
              +1
              То есть было var MyObj: TList, а потом сделали Var MyObj: TSomeArray? При такой проблеме согласен, надо какой-то уведомитель, что образовалась нештатная ситуация. Однако, подобное будет видно позже, в профайлере памяти, ведь потечет память, выделенная под массив (ссылка на него станет = nil, а содержимое останется).

              Если так, то я решаю проблему проще. У каждой ссылки на объект есть постфикс — что это такое. Например, Var MyList: TList, а потом бы стало Var MyArray: TSomeArray. Рекомендую)
              +1
              ну у нас переодически абстрактные классы стал интерфейсами становятся. компилятор ничего не говорит, но естественно при вызов FreeAndNil — AV получаем. Так что проблем с этой функцией есть
                +1
                Да, получается, это — смешанная проблема внимательности разработчика и технологии в целом. ИМХО, надо прокачивать как внимательность, так и технологию; внимательность — в первую очередь.
                  –2
                  >>это — смешанная проблема внимательности разработчика и технологии в целом.
                  ну возможно в 80х годах — это была и смешанная проблема, но в 21 веке — это проблема отсталости технологии. Печалит, что даже в совремнных версиях дельфи я не могу нормальный FreeAndNil написать. Максимум, что можно — TObjectHelper.FreeAndNil [ TMyObject ] (MyObject) // вместо [] — угловые скобки читать
              –5
              Гораздо проще просто запретить использование freeAndNil.
              А проблема висячих ссылок решается использованием:
              — объектов передаваемых по значению (record и old-style object) вместо class,
              — динамических массивов вместо контейнеров хранящих ссылки на class,
              — интерфейсов.
              • UFO just landed and posted this here
                  0
                  пишу на Python, C# и Java в случае вынужденной самообороны ;) связи с делфевым FreeAndNil не вижу ;) в общем это либо мелкий троллинг либо книжек недочитали ;)
                  • UFO just landed and posted this here
                  0
                  не знаю почему вас заминусовали, может потому, что вы использование интерфейсов не поставили на первой место? ;)
                  а про остальное не сказали, что это «устаревшие технологии» и при божеской архитектуре все эти извраты ненужны? ;)

                  а про FreeAndNil могу с вами согласится ;) прекрасно обхожусь без него :)
                    0
                    Да, непонятно за что минусы :)
                    Я постоянно использую интерфейсы, и в курсе про SIL sourceforge.net/projects/sil/
                    но для многих DTO интерфейсы — уже больше чем необходимо хотя бы потому что кода больше в разы.
                  –1
                  (wrong place)
                    +1
                    как человек, пишущий 15 лет на Delphi, не смог пройти мимо ;)
                    поиск решения это похвально, но сама по себе проблема надумана ;)
                    про FastMM вам уже сказали — он бешено рулит, если мне не изменяет память, с 2004 года… а в 2007-й Delphi так и вообще встроен(вы в курсе? ;) и включается 1-й строкой.
                    если начать говорить про архитектуру, то можно вспомнить, что разделение ответсвенности — это хорошо ;) и тогда возникает вопрос — а с чего это вы так ресурсами жонглируете что они у вас освоброждаются где попало?
                    еще можно нетипизированными указателями бросатся из одного конца приложения в другой(попадались такие извращенцы, хотя Delphi сопротивляется этому до последнего), тогда никакой FreeAndNil не поможет…

                    в общем, использование FreeAndNil в надежде что это избавит от ошибок, вместо корректной архитектуры с разграничением доступа — уже костыль. а вы его «покрасили серебрянкой» ;)

                    P.S. использую исключительно Free либо интерфесы — полет нормальный :)

                    Only users with full accounts can post comments. Log in, please.