236
Адреса переменных класса
Аналогичная проблема возникает и при получении адреса переменной класса,
даже если это
происходит в функциях класса, которым мы управляем. Именно по этой причине мы и потребовали,
чтобы везде применялись дескрипторы. Благодаря опосредованной методике проблем не возникает —
при условии, что вы получаете адрес переменной класса, используете и забываете про него в течение
одного цикла. Впрочем, от хлопот, связанных с опосредованной архитектурой, можно и отказаться.
Если вы
абсолютно уверены, что адрес не сохранится до следующего вызова функции
Copy1()
, то
можете избирательно снимать требование обязательного применения дескрипторов.
Множественное наследование
Множественное наследование безопасно при условии соблюдения всех приведенных выше
рекомендаций по уходу и кормлению указателя
this
. То обстоятельство, что
this
пляшет в
памяти
при вызове функций второго и третьего базового класса, не вызовет новых проблем — это все та же
проблема с
this
, только замаскированная. Конечно, вы никогда не должны возвращать адрес объекта,
преобразованного к базовому классу, но передача
this
тоже небезопасна.
Неустойчивые объекты
Объекты, адреса которых (в отличие от адресов их ведущих указателей) передаются за пределы вашей
зоны контроля — скажем, при вызове системной функции — необходимо сначала вывести из
очищаемого пространства. Самое простое решение — создать объект-операцию, которая перемещает
свой объект и вызывает системную функцию, когда оказывается в новом безопасном месте.
Уплотнение на месте
Очевидный недостаток алгоритма Бейкера заключается в напрасной потере половины памяти.
Существует и другой, мене очевидный недостаток — при каждом проходе все объекты копируются из
одного места памяти в другое. Такое копирование может отрицательно повлиять на быстродействие
программы. Обе проблемы решаются в другом алгоритме, который называется
уплотнением на месте
(compaction in place). Вместо двух половин существует единое пространство, а в процессе уплотнения
все объекты смещаются вниз. На следующей диаграмме показано
состояние памяти до и после
уплотнения.
До
После
Копирование объектов должно происходить в правильном порядке, снизу вверх, в противном случае
объекты будут накладываться друг на друга. Этого можно добиться двумя способами: отсортировать
ведущие указатели перед началом перебора или изначально хранить их в отсортированном порядке.
Хранить ведущие указатели в двусвязном списке, отсортированном по
адресу указываемого объекта,
довольно просто — при условии, что вы готовы потратить лишнюю пару слов для указателей на
следующий и предыдущий элемент. Шаблон ведущего указателя и дескрипторы аналогичны тем,
которыми мы пользовались до настоящего момента. Базовый класс
VoidPtr
был усовершенствован
для хранения экземпляров в связанном списке.
Базовый класс VoidPtr
Память под объекты всегда выделяется снизу вверх.
Если новые объекты
VoidPtr
всегда будут
добавляться в конец связанного списка, то список всегда будет отсортирован по возрастанию адресов