Ранее мы говорили, что код компонента TComboBox
обеспечивает перенос элементов при удалении и последующем создании окна. Но в данном случае этот код даже не догадывается, что после удаления окно может быть создано ещё раз, и потому механизм переноса не задействуется. Вновь созданное окно компонента ComboBox1
не получает в свой список ни одного элемента, что и приводит к тому, что свойство Items.Count
равно нулю. Но динамическая память, выделенная в методе AddComboItem
остается не освобождённой. В результате имеем утечку памяти вместо исключения. Кроме того, имеем утечку и других ресурсов, т.к. код, ответственный за удаление окна фрейма, на этот момент уже отработал и не будет запущен еще раз, чтобы удалить вновь созданное окно.
Решением проблемы может стать уже опробованный способ: нужно обрабатывать сообщение WM_DESTROY
, посылаемое фрейму, выполнять в нем все те же проверки, что и в листинге 3.65, и при необходимости освобождать память, которую нельзя освободить в деструкторе.
Примечание
Если бы мы попытались использовать наследника от класса, например, TPanel
вместо TFrame
, ошибка при завершении работы программы возникла бы, компоненту TPanel
не назначается родитель по умолчанию, и попытка создания его окна в деструкторе закончилась бы неудачей. Назначение родителя по умолчанию приводит еще к одному интересному эффекту: мы можем добавлять в ComboBox1
элементы до того, как будет назначено свойство Parent
фрейма. Ошибки не возникнет, потому что окно фрейма будет создано успешно, а при последующем назначении свойства Parent
фрейма в компоненте ComboBox1
сработает механизм переноса элементов при создании нового окна, и пользователь увидит добавленные элементы.
Главным выводом этого раздела должно стать то, что последовательность удаления визуальных компонентов в VCL очень плохо продумана (видимо, это одно из самых неудачных мест в VCL), поэтому нужно соблюдать особую осторожность в тех случаях, когда освобождение ресурсов удаляемого оконного компонента может быть связано с обращением к его окну. Деструктор для этих целей, как мы убедились, не подходит, удаление следует выполнять в обработчике WM_DESTROY
, проверяя, действительно ли удаляется сам компонент, а не только его окно.
Глава 4
Разбор и вычисление выражений
Перед программистом нередко возникает задача вычисления арифметических или иных выражений, не известных на этапе компиляции программы. Готовых средств для этого в Delphi нет. В Интернете можно найти компоненты и законченные примеры вычисления выражений, но нередко требуется создать что-то свое. В этой главе мы рассмотрим способы программного разбора и вычисления арифметических выражений. Кроме самих примеров будут изложены основы теории синтаксического анализа, с помощью которой эти примеры написаны. Эти сведения не только помогут лучше понять приведенные примеры, но и позволят легко написать код для синтаксического разбора любых выражений, которые подчиняются некоторому формальному описанию синтаксиса.
Синтаксический анализатор мы будем создавать поэтапно, переходя от простых примеров к сложным. Сначала научимся распознавать вещественное число и напишем простейший калькулятор, который умеет выполнять четыре действия арифметики над числами без учета приоритета операций. Затем наша программа научится учитывать приоритет этих операций, а чуть позже — использовать скобки для изменения этого приоритета. Далее калькулятор обретет способность работать с переменными, вычислять функции и возводить в степень, т.е. станет вполне полноценным. И на последнем этапе мы добавим лексический анализатор — средство, которое формализует разбор выражений со сложной грамматикой и тем самым существенно облегчает написание синтаксических анализаторов.
4.1. Синтаксис и семантика
Прежде чем двигаться дальше, введем базовые определения. Языком мы будем называть множество строк (в большинстве случаев это будет бесконечное множество). Каждое выражение (в некоторых источниках вместо "выражение" употребляются термины "предложение" или "утверждение") может принадлежать или не принадлежать языку. Например, определим язык так: любая строка произвольной длины, состоящая из нулей и единиц. Тогда выражения "000101001" и "1111" принадлежат языку, а выражения "5х" и "R@8" — нет.
Синтаксисом называется набор правил, которые позволяют сделать заключение о том, принадлежит ли заданное выражение языку или нет.
Читать дальше
Конец ознакомительного отрывка
Купить книгу