русс | укр

Мови програмуванняВідео уроки php mysqlПаскальСіАсемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование


Linux Unix Алгоритмічні мови Архітектура мікроконтролерів Введення в розробку розподілених інформаційних систем Дискретна математика Інформаційне обслуговування користувачів Інформація та моделювання в управлінні виробництвом Комп'ютерна графіка Лекції


Недоліки звичайних вказівників


Дата додавання: 2014-04-22; переглядів: 887.


Використоввати вказівники з контейнерами, складнішими ніж прості масиви, доволі складно. По-перше, якщо елементи контейнера зберігаються не послідовно в пам’яті, а сегментовано, то методи доступу до них значно ускладнюються. Ми не можемо в цьому випадку просто інкрементувати вказівник для одержання наступного значення. Наприклад, при русі від елемента до елемента у зв’язному списку ми не можемо по замовчуванню припускати, що кожен наступний є сусідом попереднього, доводиться йти по ланцюжку посилань.

До того ж, нам може знадобитися зберігати адресу певного елемента контейнера у змінній-вказівнику, щоб у майбутньому мати можливість доступу до нього. Що трапиться зі значнням вказівника, якщо ми вставимо чи видалимо елемент з контейнера? Він не вказуватиме на правильну адресу.

Одним з розв’язків цієї проблеми є створення класу «інтелектуальних вказівників». Об’єкт такого класу звичайно є оболонкою для методів, які працюють із звичайними вказівниками. Оператори ++ і * перезавантажуються і тому знають, як працювати з елементами контейнера навіть якщо вони розміщені не послідовно в пам’яті або міняють своє розміщення.

Крім того, що ітератори є «розумними вказівниками» на елементи контейнерів, вони відіграють ще одну важливу роль в STL: Вони визначають, які алгоритми використовувати з якими контейнерами.

Справа в тому, що теоретично можна використати будь-який алгоритм по віднощенню до будь-якого ітератора. Але деякі алгоритми надзвичайно неефективні по відношенню до деяких контейнерів. Наприклад, алгоритм sort() неефективний по відношенню до контейнерів, які не мають можливості довільного доступу. А для ефективної роботи алгоритму reverse необхідний контейнер, що надає можливість і прямого, і зворотнього проходження.

Ітератори пропонують дуже елегантний вихід з цього становища. Вони дозволяють визначати відповідність алгоритму контейнеру. Ітератор можна уявляти собі у вигляді кабеля, що з’єднує алгоритм і контейнер. Не всі кабелі можна приєднати до певного контейнера чи до певного алгоритму. Загалом нам потрібно 5 типів ітераторів, вони зображені на рисунку 10.2

 

Рисунок 10.2

Якщо алгоритму потрібно лише просунутися на один крок по контейнеру для здійснення послідовного читання (але не запису), він може використовувати вхідний ітератор для зв’язування себе з контейнером. В реальній практиці вхідні ітератори використовуються не з контейнерами, а при читанні з файлів чи з потоку cin.

Якщо ж алгоритму потрібно просунутися на один крок по контейнеру для здійснення послідовного запису, він може використати «вихідний» ітератор для зв’язування себе з контейнером. Вихідні ітератори використовуються при записі в файли чи в потік cout.

Якщо алгоритму потрібно пересуватися вперед, але при цьому здійснювати і запис, і читання, то доведенться використовувати «прямий» ітератор.

Якщо алгоритму потрібно пересуватися і вперед, і назад по контейнеру, він використовує двонапрямлений ітератор.

Нарешті, якщо алгоритму потрібний негайний доступ до довільного елемента контейнера без всяких поелементних пересувань, використовується ітератор «довільного доступу». Він схожий на масив своєю можливістю звертатися безпосередньо до потрібного елемента.

В таблиці 9.6 показано, які операції підтримуються якими ітераторами.

Тип ітератора Крок вперед ++ Читання value=*i Запис *i=value Крок назад -- Довільний доступ []
Довільного доступу * * * * *
Двонапрямлений * * * *  
Прямий * * *    
Вхідний *   *    
Вихідний * *      

Всі ітератори підтримують оператор ++ для просування вперед по контейнеру. Вхідний ітератор може використовуватися з оператором * справа від знаку рівності (але не зліва). Вихідні ітератори можуть використовуватися з оператором *, але розміщеним зліва від знаку рівності.

Прямий ітератор підтримує і запис, і читання, а двонапрямлений ітератор може бути як інкрементований, так і декрементований. Ітератор довільного доступу підтримує оператор [] та прості арифметичні операції + і – для швидкісного звертання до будь-якого алгоритму.

Алгоритм завжди може використовувати ітератори з більш широкими можливостями, ніж йому потрібно. Наприклад, якщо потрібний прямий ітератор, цілком нормальним вважається використання двонапрямленого ітератора чи ітератора з довільним доступом.

 


<== попередня лекція | наступна лекція ==>
Ітератори | Відповідність алгоритмів контейнерам


Онлайн система числення Калькулятор онлайн звичайний Науковий калькулятор онлайн