
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.217.4] |
![]() |
|
Страницы: (245) « Первая ... 235 236 [237] 238 239 ... 244 245 ( Перейти к последнему сообщению ) |
![]() |
Сообщ.
#3541
,
|
|
Ась? Что, где, хтозвал?
Во всех (наверное) до 1998-го года издания, в VC6 в частности. Объявленная в заголовке цикла переменная вообще-то объявлена ДО его блока {}, т.к. заголовок не является его частью, поэтому логично, чтобы она была нелокальной по отношению к телу цикла. В Стандарте имеется несколько исключений из общих правил ради всеобщего удобства, и локальность объявленной в заголовке переменной одно из них. Она не поддерживает даже C++98. Вышла за несколько месяцев до ратификации. Там много чё было не по Стандарту, даже STL образца 94-го кода, кажись. Помню, как коллега в 2002-м заявил, что "уже пробовал как-то эту хрень (STL - прим. Q), выматерился и навсегда зарёкся её юзать", там вектора сторадж перераспределяли по одному итему ![]() Однако несмотря, VC6 оказалась очень успешной. MS потом ещё чёртисколько, вплоть до VS2008, вроде бы, по дефолту вели себя как VC6 ради обратной совместимости, и циклолокальность переменных в их заголовках надо было включать руками /Zc:forScope. Бесило. |
![]() |
Сообщ.
#3542
,
|
|
Сообщ.
#3543
,
|
|
|
korvin
В дельфи цикл for - это специальная конструкция, заточенная ("оптимизированная") на исполнение цикла с фиксированным числом повторений. В ней, в отличие от while и repeat, во-первых, кол-во повторений вычисляется один раз перед началом цикла, во-вторых, управляющая переменная (счетчик цикла) носит формальный характер: ее нельзя изменять в теле цикла, и компилятор (даже при отключенной оптимизации) вправе оптимизировать цикл на свое усмотрение - держать значение счетчика в регистре, не записывая его в формальную переменную (ни в процессе счета, ни по окончании цикла), и вести счет как в прямом, так и в обратном направлении. Отсюда и требование\рекомендация не использовать значение счетчика после окончания цикла, поскольку это "противоречит концепции". Хотя, если такое использование встречается, то компилятор, несмотря на варнинг "may be undefined", все же пытается сохранить значение счетчика на выходе, возможно ценой перестройки цикла. Например, D7 в простом цикле, в котором счетчик используется только в качестве индекса массива (типа a[i]:=0), использует обратный счет до 0. Но если после цикла вставить обращение к счетчику, то несмотря на варнинг, компилятор перестроит цикл на прямой счет и в конце сохранит значение счетчика. Поэтому, не исключено, что этот варнинг - чисто предупредительный, что так делать не хорошо, но в принципе можно. Но гарантий, разумеется, никто дать не может, поэтому лучше не рисковать, и в случае break\exit самому сохранять значение счетчика в другую переменную. |
![]() |
Сообщ.
#3544
,
|
|
Цитата leo @ В дельфи цикл for - это специальная конструкция, заточенная ("оптимизированная") на исполнение цикла с фиксированным числом повторений. Дело не в этом, for везде под это "заточен", только в нормальных языках ты можешь сам решить, в каких случаях тебе это надо, а в каких -- нет, просто использованием внутренней или внешней переменной. |
![]() |
Сообщ.
#3545
,
|
|
Еще один Делфизм:
Сделал я такой набор классов: ![]() ![]() IWriter = interface procedure Write(S: string); end; TWriter = class(InterfacedObject, IWriter) private FLines: TStringList; public constructor Create; destructor Destroy; override; procedure Write(S: string); end; TTxtWriter = class(TWriter, IWriter) public procedure Write(S: string); override; end; TXmlWriter = class(TWriter, IWriter) public procedure Write(S: string); override; end; constructor TWriter.Create; begin inherited; FLines := TStringList.Create; end; destructor TWriter.Destroy; begin FLines.Free; inherited; end; procedure TWriter.Write(S: string); begin FLines.Add(S); end; procedure TTxtWriter.Write(S: string); begin inherited Write(TimeToStr(Time) + #9 + S); end; procedure TXmlWriter.Write(S: string); begin inherited Write('<ITEM time="' + TimeToStr(Time) + '">'); inherited Write(''#9 + S); inherited Write('</ITEM>'); end; и примерно такой код работы с ними: ![]() ![]() TMainForm = class(TForm) ... private FTxtWriter: IWriter; FXmlWriter: IWriter; ... end; ... procedure TMainForm.FormCreate(...); begin FTxtWriter := TTxtWriter.Create; FXmlWriter := TXmlWriter.Create; end; procedure TMainForm.FormDestroy(...); begin FXmlWriter.Free; FTxtWriter.Free; end; procedure TMainForm.BuildButtonClick(...); begin Build(FTxtWriter); Build(FXmlWriter); end; procedure TMainForm.Build(W: IWriter); begin ... // some W.Write calls end; Вначале я вспомнил, что интерфейснутые объекты в Делфи имеют счетчик ссылок и убрал вызовы Free в FormDestroy. Однако при повторном нажатии на кнопку Build выдало AV по нулевому адресу. Сделал пошаговую отладку, обнаружил, что возникает это AV при попытке доступа к FLines. Какого черта? Убрал деструктор TWriter, попробовал снова --- опять AV на том же месте, только адрес теперь не нулевой. Какого черта? Часть Вторая. Если избавиться от интерфейсов и использовать тип TWriter там, где использовался интерфейс, то все ОК. Если дело не в лыжах, то где у меня косяк? |
Сообщ.
#3546
,
|
|
|
А некорректная попытка доступа к FLines в каком месте?
|
![]() |
Сообщ.
#3547
,
|
|
А TStringList такой тупой, что не сообразит очиститься при своём разрушении?
|
Сообщ.
#3548
,
|
|
|
А как он узнает, что разрушен? В Delphi же объекты все ссылки и деструкторы полей не вызываются сами.
Или я уже все забыл с холиваров? |
![]() |
Сообщ.
#3549
,
|
|
Цитата D_KEY @ А некорректная попытка доступа к FLines в каком месте? В TWriter.Write. |
Сообщ.
#3550
,
|
|
|
Т.е. типа объект удалился до того, как сделали Write? Жесть.
А подсчет ссылок там не надо как-то инициализировать или ещё что-нибудь такое? |
![]() |
Сообщ.
#3551
,
|
|
а какой компилятор смог это переварить?
|
Сообщ.
#3552
,
|
|
|
![]() |
Сообщ.
#3553
,
|
|
Цитата D_KEY @ Вообще-то вызовут его деструктор. Другое дело, а вызовут ли? Тоже запамятовал, эти их дурацкий мульон правил и рать исключений из них... А как он узнает, что разрушен? В Delphi же объекты все ссылки и деструкторы полей не вызываются сами. Добавлено Цитата D_KEY @ Ты не прав. Это бред. Создавать объект со счётчиком равным 0? Не, Дельфи не убивали, он убился сам свои весом. Жесть |
![]() |
Сообщ.
#3554
,
|
|
Цитата D_KEY @ А подсчет ссылок там не надо как-то инициализировать или ещё что-нибудь такое? Да я вот и думаю, что-то с подсчетом. Цитата Shaggy @ а какой компилятор смог это переварить? XE2, а что не так? Цитата D_KEY @ не твой случай? Да, видимо мой. Цитата D_KEY @ Прочитал эту статью. Жесть. Ага, особенно вот это: Цитата Думаю, никто не виноват. Не нужно так делать. Врядли в языке без сборщика мусора можно было бы реализовать интерфейсы с управляемым временем жизни более удобно. Разве что принудить программиста явно вызывать _AddRef и _Release. Сомневаюсь, что это было бы удобнее. Можно, #$%^&, можно было. Аж два примера: C++ и Objective-C. |
Сообщ.
#3555
,
|
|
|
Цитата korvin @ Дело не в этом, for везде под это "заточен" Так уж и везде? В си конструкция for отличается от общего вида do\while лишь синтаксисом - условия инициализации, окончания и продолжения цикла записываются в одну строчку, но они могут быть совершено любыми, в т.ч. и пустыми. VB-шный for вроде бы ближе к дельфийскому, но в нем управляющая переменная м.б. не только ordinal типа, но и вещественного, и ва-аще любого iterator-based (с операторами +,-,>=,<=). А значит в VB перед входом в цикл вычисляется\фиксируется не кол-во повторений, а лишь конечное значение итератора, и соотв-но никакой особой "заточенности" по сравнению с обычным do\while нет. Аглицкая вики в отношении Loop variable scope and semantics не делит языки и компиляторы на "нормальные" и не очень, а лишь подчеркивает, что реализации\правила м.б. different, в т.ч. и c "becomes undefined", и объясняет преимущества таких ограничений в плане оптимизации выполнения цикла. |