А. Григорьев - О чём не пишут в книгах по Delphi

Тут можно читать онлайн А. Григорьев - О чём не пишут в книгах по Delphi - бесплатно ознакомительный отрывок. Жанр: comp-programming, издательство БХВ-Петербург, год 2008. Здесь Вы можете читать ознакомительный отрывок из книги онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    О чём не пишут в книгах по Delphi
  • Автор:
  • Жанр:
  • Издательство:
    БХВ-Петербург
  • Год:
    2008
  • Город:
    СПб
  • ISBN:
    978-5-9775-019003
  • Рейтинг:
    4.25/5. Голосов: 81
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 80
    • 1
    • 2
    • 3
    • 4
    • 5

А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание

О чём не пишут в книгах по Delphi - описание и краткое содержание, автор А. Григорьев, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.

Для программистов

О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок

О чём не пишут в книгах по Delphi - читать книгу онлайн бесплатно (ознакомительный отрывок), автор А. Григорьев
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Чтобы показать, насколько коварна эта ошибка, рассмотрим следующий код (листинг 3.42, из того же примера RecordCopy на компакт-диске).

Листинг 3.42. Сокрытие ошибки при низкоуровневом копировании записи со строкой

procedure TForm1.Button2Click(Sender: TObject);

var

Rec: TSomeRecord;

S: string;

procedure CopyRecord;

var

LocalRec: TSomeRecord;

begin

LocalRec.SomeField := 10;

LocalRec.Str := 'Привет!';

Move(LocalRec, Rec, SizeOf(TSomeRecord));

end;

begin

CopyRecord; S := 'Пока!';

Label1.Caption := Rec.Str;

end;

Or предыдущего случая этот пример отличается только тем, что в нем нет вызовов UniqueString, и строки указывают на литералы в сегменте кода, которые никогда не удаляются. На экране получаем вполне ожидаемое Привет!. Обнулять указатель здесь уже нет смысла, потому что освобождать литерал менеджер памяти все равно не будет. Так ошибка оказалась скрытой.

Продолжим наши эксперименты. Запустим пример RecordCopy и понажимаем попеременно кнопки Button1и Button2. Мы видим, что результат не зависит от порядка, в котором мы нажимаем кнопки.

Модифицируем код в локальной процедуре обработчика Button1Click: уберем из строки "Hello!!!" восклицательные знаки, сократив ее до "Hello". Теперь можно наблюдать интересный эффект: если после запуска нажать сначала Button1, то никаких изменений мы не заметим. А вот если кнопка Button2будет нажата раньше, чем Button1, то при последующих нажатиях Button1никаких видимых эффектов не будет. Это связано с тем, что теперь строка "Hello" не равна по длине строке "Good bye", поэтому разместится ли "Good bye" в том же месте памяти, где раньше была "Hello", или в каком-то другом, зависит от истории выделения и освобождения памяти. Если мы начинаем "с чистого листа", память после строки "Hello" останется свободной, поэтому туда можно поставить более длинную строку. А вот если раньше память уже выделялась и освобождалась (внутри методов TLabel), то тот кусочек свободной памяти, который достаточен для "Hello", слишком мал для "Good bye", и эта строка размещается в другом месте. А там, куда указывает Rec.Str, остается мусор, работать с которым нормально невозможно, поэтому при попытке присвоить его свойству Label1.Captionпоследнее не меняется (эффект наблюдается только до Delphi 7 включительно; в более новых версиях Delphi используется новый менеджер памяти FastMem, который немного по-другому размещает строки в памяти, поэтому с ним зависимости от порядка нажатия кнопок не будет).

Примечание

Если увеличить длину строки "Привет!" хотя бы на один символ, чтобы она была не короче, чем "Good bye" (или наоборот, сократить его так. чтобы оно стало короче "Hello"), мы снова увидим, что порядок нажатия кнопок не влияет на результат. Это происходит потому, что строка "Hello" размещается там, где раньше была строка "Привет!", а вот "Good bye" там уже не помещается. Если же обе строки там помещаются (или обе не помещаются), они снова оказываются в одной области памяти. Внимательный читатель может спросить: а при чем здесь длина строки "Привет!", если эта строка хранится в сегменте кода и никогда не освобождается? Дело в том, что когда мы присваиваем эту строку свойству Label1.Caption, внутри методов TLabelпроисходит ее перенос в динамическую память для внутренних нужд этого класса.

Даже на таком простом примере видно, насколько коварна эта ошибка и как незначительные изменения в коде могут кардинально изменить ее проявления. Между тем приведенный здесь код — плод долгого "приручения" этой ошибки, чтобы она всегда проявлялась предсказуемым образом. Но даже сейчас мы не можем дать полной гарантии, что у кого-то из читателей из-за какой-то неучтенной мелочи не возникнет ситуация, когда эта ошибка проявляется как-то по-другому (как мы уже видели, даже в разных версиях Delphi эта ошибка проявляет себя немного по-разному). В реальных проектах все гораздо сложнее, и поведение программы из-за этой ошибки может стать таким неожиданным, а проявление этой ошибки — настолько далеким от того места, где она сделана, что впору будет "прыгать вокруг компьютера с бубном", изгоняя бесов. Чтобы не оказаться в таком положении, нужно очень аккуратно работать со строками (а также с другими автоматически финализируемыми типами: динамическими массивами, интерфейсами, вариантами), чтобы тот код, который неявно генерирует компилятор, не оказался в тупике. Чаще всего проблемы возникают при побайтном копировании переменной типа AnsiString(не обязательно в составе записи) или при работе с ней как с указателем другого типа. Это не значит, что приводить AnsiStringк другим указателям категорически нельзя — ранее мы уже делали это, и вполне успешно. Но, применяя любой низкоуровневый инструмент к таким строкам, разработчик должен четко представлять, как это отразится на внутренних механизмах работы с ними. Иначе — вот такая непонятная ошибка.

Еще одна ситуация, когда записи со строками могут преподнести сюрприз — выделение динамический памяти для них. Динамическую память можно выделить двумя способами: с помощью процедуры Newили GetMem(освобождать ее надо, соответственно, с помощью Disposeили FreeMem). Для записей, не содержащих строки, эти способы практически эквивалентны, за исключением того, что при использовании Newобъем выделяемой памяти определяет компилятор, поэтому Newсчитается более безопасным вариантом. Если же запись содержит строку, то эта строка должна быть инициализирована, иначе попытка работы с ней приведет к ошибке. Процедура GetMemничего не делает с содержимым выделяемой ею памяти, и строка остается неинициализированной, в то время как Newвыполняет инициализацию. Это не значит, что GetMemнепригодна для выделения памяти для такой записи, просто после вызова GetMemнужно не забыть вызвать специальную процедуру Initialize, которая правильно инициализирует строки в записи. Соответственно, прежде чем удалить такую запись с помощью FreeMem, необходимо вызвать процедуру Finalizeдля финализации строк. Это создает дополнительные проблемы, не давая никаких преимуществ, поэтому целесообразнее все-таки использовать Newи Dispose.

Преимущество GetMemперед Newзаключается в том, что за один вызов GetMemможно выделить память сразу для нескольких записей (с последующей их ручной инициализацией, конечно же), в то время как Newвыделяет память только для одного экземпляра записи. Но с появлением в языке динамических массивов это преимущество тоже перестало быть особо полезным. Проще объявить динамический массив из записей и создать требуемое число элементов в нем — компилятор сам позаботится об инициализации таких переменных. Поэтому мы рекомендуем отказаться от GetMemпри выделении памяти под записи со строками, а если уж вы столкнулись с ситуацией, когда без этого совсем никак, не забывайте вызывать Initializeи Finalize.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


А. Григорьев читать все книги автора по порядку

А. Григорьев - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




О чём не пишут в книгах по Delphi отзывы


Отзывы читателей о книге О чём не пишут в книгах по Delphi, автор: А. Григорьев. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x