11.2 Методы классов

Предыдущая  Содержание  Следующая V*D*V

Как заткнуть эту конкретную утечку памяти? Утечка происходит в момент, когда error() возвращается в основной цикл. Либо мы собираем и освобождаем все части выражения до выполнения longjmp(), либо нужен другой способ освобождения памяти, выделенной для узлов.

Сбор частей является безнадёжным делом, потому что они хранятся различными функциями активации, вовлечёнными в алгоритм рекурсивного спуска. Только каждая активация знает, что должно быть освобождено, то есть вместо longjmp() мы должны были бы справиться с ошибкой, ведущей в каждую функцию. Это, вероятно, развалится при дальнейшем расширении программы.

Проектирование механизма возврата ресурсов является намного более систематическим подходом для решения данной проблемы. Если мы знаем, каким узлам дерева выражения в настоящее время выделена память, то можем легко удалить их и освободить память в случае ошибки. Нам требуются версии new() и delete(), поддерживающие линейный список выделенной памяти для узлов, двигаясь по которому функции, подобные reclaim(), могут освободить память. Короче говоря, для узлов дерева выражений надо переписать то, что делают new() и delete().

delete() отсылается к объектам, то есть это метод, которому можно отдать динамическую связь, чтобы его можно было переписать для поддерева иерархии классов. new(), однако, отсылается к описанию класса. Если мы хотим отдать new() динамическую связь, то должны добавить её указатель на описание класса объекта описания класса, к которому мы хотим отослать new():

 

OOC_Class_Methods

 

С такой договорённостью мы можем передать new() динамическую связь для вызова

 

new(Node, ...)

 

Однако создаётся проблема для описаний описаний классов, то есть правой стороны этой картинки. Если начать вводить новые компоненты методов в описания метаклассов, таких как NodeClass, мы больше не сможем использовать struct Class для их хранения, то есть наша схема должна быть расширена по крайней мере ещё один уровень справа, прежде чем можно было бы связать их с исходным Class.

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

Существующих описаний классов меньше, чем других объектов; поэтому стоимость хранения адреса метода непосредственно в описании класса, к которому применяется метод, не столь высока, как это было бы в случае других объектов. Мы называем такие методы методами класса — они применимы к описанию класса, в котором хранятся, а не к объектам, совместно использующим это описание класса.

Типичным методом класса, который был бы переписан для управления выделением памяти, является new(): предоставление статистики или механизма освобождения; создание объектов в зонах памяти для улучшения поведение программы при разбивке на страницы; совместное использование памяти объектами, и так далее. Могут быть добавлены другие методы класса, если мы, например, захотим обойти соглашение, по которому new() всегда вызывает конструктор ctor().

 

Предыдущая  Содержание  Следующая