Конференция "Основная" » Отложенное освобождение объектов
 
  • ggg (19.06.08 19:39) [0]
    У меня в программе некоторые объекты имеют счетчик использования. Сделано это для того, что бы они не были удалены до того, когда на них перестанут ссылаться другие объекты.
    Сначала пробывал добавить следующий код в деструктор:

    destructor TGraphicObject.Destroy;
    begin
       if UseCount > 0 then
         begin
           FMustBeFree := true;
           Exit;
         end;
    ...



    Но практически сразу же получал AV.
    Поэтому создал метод Free;


    procedure TGraphicObject.Free;
    begin
     if Assigned(Self) then
       if UseCount > 0 then
         FMustBeFree := true
       else
         inherited; // или Destroy, не важно
    end;



    Пока вроде бы проблем не наблюдается, но как-то беспокойно на душе :)
    Собственно вопросы:
    1) Destroy в любом случае удаляет объект, даже если там стоит Exit и не вызывается inherited?
    2) Метод Free не помечен как virtual, соответсвенно и мой метод не может быть отмечен как override. Безопасно ли использовать такой способ? Или правильней будет создать некий MyFreeMethod, где будет проверяться FUseCount и вызываться Free?
  • Поросенок Винни-Пух © (19.06.08 20:04) [1]
    procedure TGraphicObject.Free;
    begin
    if Assigned(Self) then

    гениально.
  • Поросенок Винни-Пух © (19.06.08 20:05) [2]
    А оунер этого волшебного объекта в курсе что кто-то там что-то там считает?

    :)
  • Игорь Шевченко © (19.06.08 20:06) [3]
    тебе надо посмотреть, как работает TInterfacedObject._Release - оно так примерно и делает, если ссылок 0, то вызывает Destroy

    Или переопределить метод FreeInstance
  • Игорь Шевченко © (19.06.08 20:06) [4]
    Поросенок Винни-Пух ©   (19.06.08 20:04) [1]


    > if Assigned(Self) then
    >
    > гениально.


    Тебе никогда не встречался Self=nil ?
  • Поросенок Винни-Пух © (19.06.08 22:30) [5]
    Мне интересно куда он там мог деться в первой же строчке собственного метода, что его проверяют на нил
  • Поросенок Винни-Пух © (19.06.08 22:34) [6]
    Сделано это для того, что бы они не были удалены до того, когда на них перестанут ссылаться другие объекты.

    То есть есть самодельный механизм подсчета и зачем-то переделываются методы дестрой и фри.

    А для чего? Для того, чтобы можно было в любой строчке собственного когда неглядя вызвать фри объекта, не опасаясь что он будет удален если на него есть ссылки?
    А не логичнее ли вызывать фри по условию, если уж автору известно есть ссылки или нет их?
  • Loginov Dmitry © (19.06.08 22:53) [7]
    > Мне интересно куда он там мог деться в первой же строчке
    > собственного метода, что его проверяют на нил



    var
     g: TGraphicObject;
    begin
     g := nil;
     g.Free;
    end;



    Что произойдет в
    g.Free

    , если
    if Assigned(Self)

    не делать?
  • Поросенок Винни-Пух © (19.06.08 22:56) [8]
    ты во внутрь самого фри не попадешь при таком раскладе
  • Loginov Dmitry © (19.06.08 23:00) [9]
    > ты во внутрь самого фри не попадешь при таком раскладе


    Free - это статический метод (фактически обычная процедура). Почему же я в нее не попаду?
  • Anatoly Podgoretsky © (19.06.08 23:09) [10]
    > Loginov Dmitry  (19.06.2008 22:53:07)  [7]

    А зачем его делать?
    Советую взглянуть генофонд или прочитать справку.
  • Поросенок Винни-Пух © (19.06.08 23:14) [11]
    Что произойдет в g.Free, если if Assigned(Self) не делать?

    Произойдет то же самое, что происходит если делать if Assigned(Self)

    g := nil;
    g := T...Create();
    g.Free;
  • Поросенок Винни-Пух © (19.06.08 23:15) [12]
    Нагляднее так:

    type
    ttt = class
     procedure test;
    end;

    procedure ttt.test;
    begin
     if Assigned(Self) then ShowMessage('yes') else ShowMessage('no');
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var t : ttt;
    begin
    t := nil;
    t := ttt.Create;
    t.Free;
    t.test;
    end;
  • Loginov Dmitry © (19.06.08 23:16) [13]
    > А зачем его делать?


    У автора реализован собственный метод Free. В нем выполняется проверка if Assigned(Self). Что произойдет в g.Free (из [7]), если if Assigned(Self) (в TGraphicObject.Free) не делать?
  • Eraser © (19.06.08 23:18) [14]
    > [0] ggg   (19.06.08 19:39)


    > if Assigned(Self) then
    >   if UseCount > 0 then

    в данном коде смущает то, что большое количество вложенных условий делает код запутанным.
    imho, уместнее
    if not Assigned(Self) then
     Exit;

  • Поросенок Винни-Пух © (19.06.08 23:20) [15]
    У автора реализован собственный метод Free. В нем выполняется проверка if Assigned(Self). Что произойдет в g.Free (из [7]), если if Assigned(Self) (в TGraphicObject.Free) не делать?

    произойдет все то же самое если её делать.
  • Loginov Dmitry © (19.06.08 23:24) [16]
    > imho, уместнее
    > if not Assigned(Self) then
    > Exit;


    имхо, нагляднее так:
    procedure TGraphicObject.Free;
    begin
     if Assigned(Self) then
     begin
       if UseCount > 0 then
         FMustBeFree := true
       else
         inherited; // или Destroy, не важно
     end;
    end;



    Но у каждого будет свое имхо и спорить, имхо, бессмысленно.
  • Loginov Dmitry © (19.06.08 23:26) [17]
    > произойдет все то же самое если её делать.


    Для чего тогда, по Вашему, в TObject.Free() реализована такая же проверка?
  • Поросенок Винни-Пух © (19.06.08 23:29) [18]
    я ж нарисовал пример в котором assigned рапортует "yes"
    и типа после этого метод уверен, что можно что-то там делать.
  • Loginov Dmitry © (19.06.08 23:55) [19]
    > я ж нарисовал пример в котором assigned рапортует "yes"
    > и типа после этого метод уверен, что можно что-то там делать.


    совать во Free() битые ссылки - ситуация ненормальная и естественно карается. А вот вызов TObject(nil).Free - это обычное дело, и без проверки на nil не обойтись.
  • ggg (20.06.08 06:03) [20]
    >> [1]
    system.pas

    procedure TObject.Free;
    begin
     if Self <> nil then
       Destroy;
    end;


    Вы считаете это глупость?

    >> [3]
    FreeInstance вызывается после Destroy, но если проверку добавить в оба метода, то да. Спасибо, помогло :)

    >> [6]
    Да, иметь возможность вызвать метод Free в любой момент не заботясь о последствиях весьма удобно.
    Заменить это уменьшением UseCount.. не безопасно. Просто, возможно несколько условий на различных стадиях работы движка, когда объект необходимо удалить. Тогда при выполнении нескольких условий счетчик может стать равным 0 до того, как объект действительно освободится.

    >>[14]
    Где-то встречал, будто опыты показали, что if...else работает быстрее, чем Exit. Не ручаюсь за достоверность, но большой разницы нет.

    >>[16]
    Насколько мне известно, эти begin..end дадут несколько другой код после компиляции, который будет выполнятся дольше. Хотя, возможно, это предрассудки моего препода по паскалю :)
  • Loginov Dmitry © (20.06.08 07:50) [21]
    > Насколько мне известно, эти begin..end дадут несколько другой
    > код после компиляции, который будет выполнятся дольше


    Разговор про наглядность, а не про скорость. Скорость тут дело десятое.


    > Хотя, возможно, это предрассудки моего препода по паскалю
    > :)


    +1 :)
  • Игорь Шевченко © (20.06.08 09:44) [22]

    > ты во внутрь самого фри не попадешь при таком раскладе


    я попаду в любой невиртуальный метод
  • ggg (20.06.08 20:06) [23]
    Ну как бы всё-равно проблемы остались -- одну и ту же проверку приходится производить дважды: в Destroy и в FreeInstance. Если есть еще предложения, буду рад выслушать.
  • Eraser © (20.06.08 20:54) [24]
    > [20] ggg   (20.06.08 06:03)


    > Где-то встречал, будто опыты показали, что if...else работает
    > быстрее, чем Exit. Не ручаюсь за достоверность, но большой
    > разницы нет.

    ох уж эта привычка применять тонкую оптимизацию где попало, а потом разгребаешь
    if then
     if then
      if then

    и еще тележку else if
 
Конференция "Основная" » Отложенное освобождение объектов
Есть новые Нет новых   [134491   +12][b:0][p:0.001]