You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
Паттерны поведения<br />
исключения память, занимаемая объектом-итератором, вообще никогда не<br />
будет освобождена.<br />
Эту ситуацию помогает исправить паттерн заместитель. Вместо настоящего<br />
итератора мы используем его заместителя, память для которого выделена<br />
в стеке. Заместитель уничтожает итератор в своем деструкторе. Поэтому,<br />
как только заместитель выходит из области действия, вместе с ним<br />
уничтожается и настоящий итератор. Заместитель гарантирует выполнение<br />
надлежащей очистки даже при возникновении исключений. Это пример<br />
применения хорошо известной в C++ техники, которая называется «выделение<br />
ресурса - это инициализация» [ES90]. В разделе «Пример кода»<br />
она проиллюстрирована подробнее;<br />
а итераторы могут иметь привилегированный доступ. Итератор можно<br />
рассматривать как расширение создавший его агрегат. Итератор и агрегат<br />
тесно связаны. В C++ такое отношение можно выразить, сделав итератор другом<br />
своего агрегата. Тогда не нужно определять в агрегате операции, единственная<br />
цель которых - позволить итераторам эффективно выполнить обход.<br />
Однако наличие такого привилегированного доступа может затруднить определение<br />
новых способов обхода, так как потребуется изменить интерфейс агрегата,<br />
добавив в него нового друга. Для того чтобы решить эту проблему,<br />
класс Iterator может включать защищенные операции для доступа к важным,<br />
но не являющимся открытыми членам агрегата. Подклассы класса<br />
Iterator (и только его подклассы) могут воспользоваться этими защищенными<br />
операциями для получения привилегированного доступа к агрегату;<br />
а итераторы для составных объектов. Реализовать внешние агрегаты для рекурсивно<br />
агрегированных структур (таких, например, которые возникают<br />
в результате применения паттерна компоновщик) может оказаться затруднительно,<br />
поскольку описание положения в структуре иногда охватывает<br />
несколько уровней вложенности. Поэтому, чтобы отследить позицию текущего<br />
объекта, внешний итератор должен хранить путь через составной объект<br />
Composite. Иногда проще воспользоваться внутренним итератором.<br />
Он может запомнить текущую позицию, рекурсивно вызывая себя самого,<br />
так что путь будет неявно храниться в стеке вызовов.<br />
Если узлы составного объекта Composite имеют интерфейс для перемещения<br />
от узла к его братьям, родителям и потомкам, то лучшее решение дает<br />
итератор курсорного типа. Курсору нужно следить только за текущим узлом,<br />
а для обхода составного объекта он может положиться на интерфейс<br />
этого узла.<br />
Составные объекты часто нужно обходить несколькими способами. Самые<br />
распространенные - это обход в прямом, обратном и внутреннем порядке,<br />
а также обход в ширину. Каждый вид обхода можно поддержать отдельным<br />
итератором;<br />
а пустые итераторы. Пустой итератор Nulllterator - это вырожденный<br />
итератор, полезный при обработке граничных условий. По определению,<br />
Nulllterator всегда считает, что обход завершен, то есть его операция<br />
IsDone неизменно возвращает истину.