Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2007.03.25;
Скачать: [xml.tar.bz2];

Вниз

Free()   Найти похожие ветки 

 
Loginov Dmitry ©   (2007-02-18 09:15) [0]

Насколько идеологически/практически правильно/неправильно подменять метод Free(), реализованный у TObject своим собственным методом Free()? В своем классе, наследуемом от TObject, я выполнил такую вот подмену, и теперь мой Free() со 100% гарантией будет вызывать метод Destroy только для реально "живых" объектов, иначе сгенерирует исключение. Теперь сомнения мучают, нет ли тут каких-нибудь неучтенных граблей?


 
Loginov Dmitry ©   (2007-02-18 09:22) [1]

Реализация практически таже, что и у TObject


 procedure TMatrix.Free;
 begin
   if Self = nil then Exit;
   if not MatrixRefIsValid(Self) then
     DoMatrixError(matSRefIsNotMatrix, "procedure TMatrix.Free");
   Destroy;  
 end;


 
Ketmar ©   (2007-02-18 09:59) [2]

а чем не приглянулся нормальный сборщик мусора?


 
Аноним   (2007-02-18 10:09) [3]

Предположим, ты поместил свой  объект TMatrix в ObjectList
и предполагаешь, что при разрушении листа твой объект разрушится.
Так и будет, только твой метод  Free при этом никто не вызовет
(точно так же случится, если твой объект будет разрушаться кем то ,кто не знает про класс TMatrix)
Неправильно короче.
Переопределяй деструктор, или BeforeDestruction - то есть виртуальные методы, а не статические


 
Loginov Dmitry ©   (2007-02-18 10:09) [4]

> а чем не приглянулся нормальный сборщик мусора?


Причем тут сборщик мусора?
Чем он должен был мне приглянуться?


 
Loginov Dmitry ©   (2007-02-18 10:18) [5]

> Предположим, ты поместил свой  объект TMatrix в ObjectList
> и предполагаешь, что при разрушении листа твой объект разрушится.
> Так и будет, только твой метод  Free при этом никто не вызовет


Это-та да. Но на такие жертвы пойти можно ради повышения качества.


> Переопределяй деструктор, или BeforeDestruction - то есть
> виртуальные методы, а не статические


А вот с виртуальными методами уже напряжнее. При удалении объекта указатель на ТВМ чаще всего обнуляется, поэтому обращение к любому виртуальному методу приведет к AV.


 
Аноним   (2007-02-18 10:29) [6]


> А вот с виртуальными методами уже напряжнее. При удалении
> объекта указатель на ТВМ чаще всего обнуляется, поэтому
> обращение к любому виртуальному методу приведет к AV.


В случае повторного деструктора статичность метода  нас не спасет,потому что, судя по if not MatrixRefIsValid(Self) then
все равно предстоит обращение к полям.

Если брать ситуацию, когда ссылка при разрушении обнуляется, то вот как раз в родном Free уже все сделано, в этом случае виртуальный метод от разрушенного объекта просто не будет вызван.


 
Loginov Dmitry ©   (2007-02-18 10:44) [7]

> В случае повторного деструктора статичность метода  нас
> не спасет,потому что, судя по if not MatrixRefIsValid(Self)
> then
> все равно предстоит обращение к полям.


Повторюсь, что MatrixRefIsValid(Self) гарантированно возвращает True для "живых" объектов. Для всех прочих объектов (и "необъектов") эта функция возвращает False. Гарантия - 100%. Почему - это уже вопрос по реализации данной функции.


 
Ketmar ©   (2007-02-18 11:05) [8]

> Loginov Dmitry ©   (18.02.07 10:09) [4]
а тем, что подобные "защиты" делают для предотвращения "double destruction" и "stale pointers". с GC такой ерунды просто не бывает.


 
Loginov Dmitry ©   (2007-02-18 11:18) [9]

Приведи пример использования нормального сборщика мусора для предотвращения "double destruction" и "stale pointers". Может тогда до меня дойдет, что ты имеешь ввиду...


 
Ketmar ©   (2007-02-18 11:23) [10]

> Loginov Dmitry ©   (18.02.07 11:18) [9]
читай статьи про GC. или подумай, как может появиться первое/второе в системе, где
а) объекты никто руками не уничтожает, и, следовательно,
б) все указатели на управляемые объекты всегда валидны.


 
Юрий Зотов ©   (2007-02-18 11:33) [11]

> Loginov Dmitry

> ради повышения качества

Я бы не сказал, что это повышение качества. Скорее понижение. Потому что во всех сотнях (если не тысячах) мест, где Free вызывается из VCL, будет вызван "родной", а не Ваш Free. В итоге желаемого Вы все равно не добъетесь, а результатом будет только путаница, ничего более.

Так что - какое же это "повышение качества"? Это понижение.


 
Loginov Dmitry ©   (2007-02-18 11:37) [12]

Так я и не понял, на решение какой проблемы был направлен пост [2]?


 
Ketmar ©   (2007-02-18 11:40) [13]

> Loginov Dmitry ©   (18.02.07 11:37) [12]
мётлы обещали скоро подвезти. записываю в очередь.


 
Loginov Dmitry ©   (2007-02-18 11:49) [14]

> [11] Юрий Зотов ©   (18.02.07 11:33)

> Я бы не сказал, что это повышение качества. Скорее понижение.
> Потому что во всех сотнях (если не тысячах) мест, где Free
> вызывается из VCL, будет вызван "родной", а не Ваш Free


Я бы очень сильно удивился, еслиб вдруг где-нибудь из VCL был вызван мой Free :))


> В итоге желаемого Вы все равно не добъетесь, а результатом
> будет только путаница, ничего более.


Мне достаточно такого результата, чтобы для объекта AObject: TMatrix был был вызван мой метод Free(). Чтобы система адекватно реагировала на такие ситуации:

AObject := TByteMatrix.Create;
AObject.Free;
AObject.Free;

И при втором вызове Free() обращение к виртуальному методу Destroy не произошло.
Хорошо, если кроме путаницы (хотя какая тут еще путаница может быть) ничего плохого не произойдет. Для меня главное, чтобы мой метод Free() из-за такой вот подмены ничего не "сломал".


> Так что - какое же это "повышение качества"? Это понижение.


Это Ваше личное мнение. Спорить в Вами я не могу.


 
Loginov Dmitry ©   (2007-02-18 11:50) [15]

> мётлы обещали скоро подвезти. записываю в очередь.


И давно ты в этом бизнесе работаешь?


 
Юрий Зотов ©   (2007-02-18 11:56) [16]

> Loginov Dmitry ©   (18.02.07 11:49) [14]

AObject := TByteMatrix.Create;
TObject(AObject).Free; // Это автоматический вызов из VCL
AObject.Free; // А это Ваш вызов.

И получаем все те же грабли.

Поэтому: "В итоге желаемого Вы все равно не добъетесь, а результатом будет только путаница".


 
Loginov Dmitry ©   (2007-02-18 12:02) [17]

> AObject := TByteMatrix.Create;
> TObject(AObject).Free; // Это автоматический вызов из VCL
> AObject.Free; // А это Ваш вызов.
>
> И получаем все те же грабли.


С чего вы взяли, что получим те же грабли. Грабли будут только при таком вызове:

AObject := TByteMatrix.Create;
TObject(AObject).Free; // Это автоматический вызов из VCL
TObject(AObject).Free; // Это автоматический вызов из VCL


 
Аноним   (2007-02-18 12:05) [18]


> Я бы очень сильно удивился, еслиб вдруг где-нибудь из VCL
> был вызван мой Free :))


Удивишься, удивишься.
Дело в том, что системы имеют такое свойство - жить некоей жизнью и меняться. На это должна ставиться закладка с самого начала.\
Сейчас VCL не вызовет, а потом программа будет меняться (например даже не тобой, а другим программистом) и этот вызов появится.
А другой программист должен будет знать, что "нельзя так делать", хотя при стандартном поведении классов так делать можно.

Собственно, ты е спрашиваешь про идеологию? А не про то, чтобы "сейчас заработало".
Есть такой паттерн проектирования - называется "детонатор".
Хочешь его - на здоровье, никто тут с тобой спорить не будет


 
Loginov Dmitry ©   (2007-02-18 12:17) [19]

> Сейчас VCL не вызовет, а потом программа будет меняться
> (например даже не тобой, а другим программистом) и этот
> вызов появится.


Даже не другим программистом, а десятками и сотнями программистов. Проект очень ответственный, иначе бы я не завел данной ветки, и не стал бы выделываться в подменой метода Free(). Это я делаю с целью облегчения работы с системой, с целью своевременного обнаружения ситуаций повторного уничтожения.


> А другой программист должен будет знать, что "нельзя так
> делать", хотя при стандартном поведении классов так делать
> можно.


Почему же так делать нельзя. Можно. Хочешь - вызывай TObject(AObject).Free; Хочешь - вызывай AObject.Free; Я не считаю, что при вызове AObject.Free дополнительная проверка на существование объекта кому-то может помешать.


 
Аноним   (2007-02-18 12:31) [20]


> Loginov Dmitry ©


> Я не считаю, что при вызове AObject.Free дополнительная
> проверка на существование объекта кому-то может помешать.
>

Мне кается, ты берешь на себя не свои функции. Посмотри в VCL - там разве есть что-то подобное?

Если совсем приперло - назови метод по другому
типа
FreeCheckValid


 
Юрий Зотов ©   (2007-02-18 14:02) [21]

> Loginov Dmitry ©   (18.02.07 12:02) [17]
> С чего вы взяли, что получим те же грабли.

Из Вашего кода. После вызова стандартного Free параметр Self в Вашем Free будет битой ссылкой (но не nil). И получим те же грабли.


 
Юрий Зотов ©   (2007-02-18 14:31) [22]

> Loginov Dmitry ©

Собственно, что зря спорить? Напишите десяток строк и все увидите сами.

Делаю потомка Вашего объекта:

type
 TMyMatrix = class(TByteMatrix)
 private
   FSomeField: integer;
 public
   destructor Destroy; override;
 end;

destructor TMyMatrix.Destroy;
begin
 FSomeField  = 0;
 inherited;
end;

Теперь проверяем, как сработает Ваш Free после вызова стандартного:

procedure TForm1.Button1Click(Sender: TObject);
var
 AObject: TMyMatrix;
begin
 AObject := TMyMatrix.Create;
 TObject(AObject).Free; // VCL будет вызывать Free именно так
 AObject.Free; // А это вызов Вашего Free.
end;

И в Вашем Free получим AV - либо при вызове MatrixRefIsValid (если там есть обращения к полям объекта), либо при вызове деструктора (потому что в деструкторе TMyMatrix обращение к полям точно есть).

Я не думаю, что те самые "десятки и сотни программистов" скажут Вам "спасибо", когда в Вашей документации они прочтут одно ("вызывайте Free сколько хотите и где хотите, повторный вызов и валидность ссылок проверяются автоматически"), а на деле получат совсем другое.

Например, вставят Ваш объект (или его потомка) в TObjectList, а потом, согласно Вашей же рекомендации не придадут значения лишнему Free в своем коде и получат все то же самое AV.

PS
Дмитрий, Вы далеко не в первой тысяче пытавшихся "заместить" статический метод (или свойство), закрыв (не перекрыв, а именно закрыв) его своим с тем же именем. И еще ни разу такое "решение" ни к чему хорошему не приводило. Потому что это самые натуральные костыли. Стоит только привести Ваш класс к любому другому (или объявить переменную с любым другим типом) - и будет вызван стандартный, а не Ваш Free. Получаем двойственное поведение - и бедняги программеры будут сначала долго-долго выяснять, в чем тут дело, а потом дого-долго материться.


 
jack128 ©   (2007-02-18 14:50) [23]

Удалено модератором
Примечание: Словарный запас сокращай. Накажу


 
jack128 ©   (2007-02-18 14:52) [24]

jack128 ©   (18.02.07 14:50) [23]
А, блин.  Насчет BeforeDestruction я поторопился :-)


 
Суслик ©   (2007-02-18 15:11) [25]

2автор.
ужасный метод free.
причем ничего "со 100% гарантией" не гарантирует.

сам подумай.


 
Суслик ©   (2007-02-18 15:15) [26]

для повышения качества *очень* советую использовать FastMM в полной версии (качается в www.sourceforge.net).

В нем есть опция - проверять вызов виртуальных методов у уничтоженных объектов. Как известно деструктор виртуален. Так вот ФастММ радостно это ловит. Причем говорит:
1. Стек вызовов когда объект был создан.
2. Стек вызовов когда уничтожен.
3. Стек вызовов при вызове вирт. метода уничтоженного объекта.

Он работает многократно надежней чем твой метод, т.к. ФастММ это манагер памяти и он волен для уничтоженных блоков ставить нужные ему значения. В отладочном режиме он стави $80808080 (если не ошибаюсь). По этому адресу определяет убитость объекта.


 
Leonid Troyanovsky ©   (2007-02-18 16:09) [27]


> Loginov Dmitry ©   (18.02.07 09:15)  

> гарантией будет вызывать метод Destroy только для реально
> "живых" объектов, иначе сгенерирует исключение. Теперь сомнения

Для того, чтобы быть уверенным, что имеешь дело с живым объектом, необходима уверенность, что удерживаемая в руках ссылка валидна,
и, по крайней мере, была вовремя обнулена при разрушении объекта.

Подобные гарантии возможны, например, для механизма Notification,
т.е., среди компонентов.

Все остальное - от лукавого.

Кста, if not Assigned(..) then Destroy - делает обычный Free, т.е.,
нет смысла уточнять его здесь.
Проблема лишь в том, что ссылок на единственный объект
может быть более одной.

--
Regards, LVT.


 
Anatoly Podgoretsky ©   (2007-02-18 16:55) [28]

> Loginov Dmitry  (18.02.2007 11:50:15)  [15]

Ты не поверишь, это крупнейший распространитель метл.


 
Loginov Dmitry ©   (2007-02-20 08:07) [29]

> [20] Аноним   (18.02.07 12:31)
> Если совсем приперло - назови метод по другому
> типа
> FreeCheckValid


Придется сделать примерно также. Помещу собстенный метод Free() внутри блока условной компиляции. Добавлю статичный метод FreeMatrix, в который помещу текст [1]. Получится примерно следующее:


{$ifdef UseExtendedFree}
procedure Free;
begin
  FreeMatrix;
end;
{$ifdef UseExtendedFree}



> [21] Юрий Зотов ©   (18.02.07 14:02)
> > Loginov Dmitry ©   (18.02.07 12:02) [17]
> > С чего вы взяли, что получим те же грабли.
>
> Из Вашего кода. После вызова стандартного Free параметр
> Self в Вашем Free будет битой ссылкой (но не nil). И получим
> те же грабли.


Выдачу AV с указанием причины ошибки и места ее возникновения Вы называете граблями?


> И в Вашем Free получим AV - либо при вызове MatrixRefIsValid
> (если там есть обращения к полям объекта), либо при вызове
> деструктора (потому что в деструкторе TMyMatrix обращение
> к полям точно есть).


Вот код функции MatrixRefIsValid():

function MatrixRefIsValid(AMatrix: TMatrix): Boolean;
begin

 if AMatrix = nil then
 begin
   Result := False;
   Exit;
 end;

 Result := True;
 try
   if not IsEqualGUID(AMatrix.FLifeGUID, LifeMatrixGuid)
     {or not (TObject(AMatrix) is TMatrix)}
     {К сожалению, мы не всегда можем использовать операцию проверки IS.
      Допустим, если есть EXE и DLL, откомпилированные с Matrix32 без
      использования пакетов, то операция IS сработает некорректно. Именно
      по этой причине эту операцию в данном модуле вы нигде не найдете.}
   then
     Result := False;
 except // Обращение AMatrix.FLifeGUID может привести к исключению
   Result := False;
 end;
end;


Обращение к полю объекта находится в защищенном блоке.

А при вызове деструктора получение AV наиболее вероятно из-за обнуления указателя на VMT, а не из-за обращения к полям уничтоженного объекта. Даже если AV не возникнет, то проверка ссылки в BeforeDestruction - неплохой выход.


> [26] Суслик ©   (18.02.07 15:15)
> для повышения качества *очень* советую использовать FastMM
> в полной версии (качается в www.sourceforge.net).


Советовать мне FastMM - это лишнее. Можно и без него прекрасно обойтись.


> Для того, чтобы быть уверенным, что имеешь дело с живым
> объектом, необходима уверенность, что удерживаемая в руках
> ссылка валидна,
> и, по крайней мере, была вовремя обнулена при разрушении
> объекта.
>
> Подобные гарантии возможны, например, для механизма Notification,
> т.е., среди компонентов.


Данный механизм я давно и успешно использую.


 
Ketmar ©   (2007-02-20 09:33) [30]

> Loginov Dmitry ©   (20.02.07 08:07) [29]
> Выдачу AV с указанием причины ошибки и места ее возникновения
> Вы называете граблями?

а что, выдача AV -- это теперь "нормальное поведение"? хоть трижды место ошибки укажи -- всё равно грабли.


 
Loginov Dmitry ©   (2007-02-20 10:09) [31]

> а что, выдача AV -- это теперь "нормальное поведение"? хоть
> трижды место ошибки укажи -- всё равно грабли.


Я имел ввиду не AV, а просто генерацию собственного исключения.


 
evvcom ©   (2007-02-20 10:28) [32]

> [31] Loginov Dmitry ©   (20.02.07 10:09)
> просто генерацию собственного исключения

Да какая разница? Если ссылку на объект хранит другой объект, настрой нотификацию, как уже было сказано в [27]. Тогда никаких повторных разрушений не будет. (Ну это, правда, как настроишь :)


 
Ketmar ©   (2007-02-20 10:34) [33]

> Loginov Dmitry ©   (20.02.07 10:09) [31]
"фраза не моя, я её просто напечатал".


 
vecna ©   (2007-02-20 10:37) [34]

Удалено модератором


 
Аноним   (2007-02-20 10:53) [35]


> Loginov Dmitry ©


> Вот код функции MatrixRefIsValid():


Имхо, единственный четкий способ тут определить - валидна матница или нет - это завести некий скрытый под имплементейшн лист, в конструкторе матрицы добавлять в него селф, в деструкторе этот самый селф выкидывать, а проверять с помошью IndexOf


 
Loginov Dmitry ©   (2007-02-20 11:18) [36]

> Имхо, единственный четкий способ тут определить - валидна
> матница или нет - это завести некий скрытый под имплементейшн
> лист, в конструкторе матрицы добавлять в него селф, в деструкторе
> этот самый селф выкидывать, а проверять с помошью IndexOf


Использовать такой глобальный список я не хочу по 3-м причинам:
1 - не хочу иметь проблем при использовании многопоточности
2 - при создании большого числа объектов работа со списком начнет тормозить
3 - при компиляции модуля без пакетов в EXE и в DLL списки будут у каждого свои, и функция будет работать неверно.


 
evvcom ©   (2007-02-20 11:24) [37]

> [36] Loginov Dmitry ©   (20.02.07 11:18)

1. детский лепет.
2. большого - это миллион? Куда столько?
3. а не надо так делать. Даже в твоем случае дублирование кода класса уже не правильно.

Ты подумай все ж над тем, что в твоей консерватории что-то не так.


 
Loginov Dmitry ©   (2007-02-20 12:00) [38]

> 2. большого - это миллион? Куда столько?


А может и миллион. Мало ли...


> 3. а не надо так делать. Даже в твоем случае дублирование
> кода класса уже не правильно.


Попробуй объясни всему миру что так делать не надо.


> Ты подумай все ж над тем, что в твоей консерватории что-
> то не так.


Все так.


 
ЮЮ ©   (2007-02-20 12:05) [39]


> Loginov Dmitry ©   (20.02.07 12:00) [38]


Похоже, сомнения, мучавшие при написании subj-а, совсем прошли :)


 
evvcom ©   (2007-02-20 12:11) [40]

> [38] Loginov Dmitry ©   (20.02.07 12:00)
> Все так.

Хозяин - барин. Тогда зачем ты здесь?



Страницы: 1 2 3 4 вся ветка

Форум: "Прочее";
Текущий архив: 2007.03.25;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.58 MB
Время: 0.054 c
15-1172516915
Rouse_
2007-02-26 22:08
2007.03.25
Кто с билдером работает?


15-1172737610
Ega23
2007-03-01 11:26
2007.03.25
Не ставятся breakpoint-ы в проекте....


15-1172488794
cosinus
2007-02-26 14:19
2007.03.25
Мониторинг здоровья HDD


15-1172505169
Cyrax
2007-02-26 18:52
2007.03.25
partial в C#


15-1172667553
Knight
2007-02-28 15:59
2007.03.25
Кнопища Пуск...





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский