Дороговкази в контейнерах. STL (частина 16)




покажчики в контейнерах, STL, програмування для початківців

Контейнери STL істотно знижують складність написання коду, працюючого з динамічними структурами даних і, найголовніше, підвищують його безпомилковість. Але в деяких випадках, при роботі з великими елементами даних в контейнерах, ця техніка може породжувати неминучу втрату продуктивності. Это связано с тем, що починаючи з операції приміщення елемента в контейнер, і всі наступні переміщення елементів можуть вимагати копіювання елементів.

Примітка: Ступінь вираженості таких ефектів залежить і від типу контейнера, і від розглянутих операцій. Наприклад, операції взаємного обміну 2-х елементів в ході сортування потребуватиме 3-х копіювань для контейнера типу vector і не потребуватиме додаткових копіювань для контейнера list. Але операції початкового приміщення елемента в контейнер (push_back(), вставити() та ін.) завжди виконуються копіюванням.

Це може стати проблемою для додатка, коли операції на контейнерах критичні за часом виконання (або здаються вам такими). Є і ще більш складні випадки, коли для класу об'єктів контейнера не визначена операція копіювання, або коли об'єкти представляють собою самі посилальні об'єкти, повне копіювання для яких необхідно виконувати рекурсивними процедурами проходження по всіх посиланнях (те, що в мові Python і інших називають глибоким копіюванням).

Все працює благополучно, як і раніше - сортуємо набір записів по довільним полях і в будь-якому порядку:

16-1

(Зверніть увагу, що завершувати це додаток потрібно по Ctrl + D - End Of File ... в Widows, мабуть, по Ctrl + Z.)

Але! ... Спеціально були залишені налагоджувальні «сліди» спрацьовувань конструкторів і деструкторів записів, і записи конструюються 8 раз, а деструкція спрацьовує тільки 4, для локального масиву в точці виходу з блоку. Локальний масив для нас взагалі не представляє інтересу. Він введений для спрощення прикладу тільки як набір ініціюючих значень. А ось для записів, розміщені в контейнер, знищення записів не відбувається, і ми отримуємо відверту витік пам'яті. Але гірше того, після того як ми видаляємо елемент з контейнера (не роблячи додаткових дій), ми і не зможемо видалити запис, викликавши для неї delete. Это потому, що після виклику прати() ми втратили до запису єдиний шлях доступу через итератор (в коді показаний цикл з прати(), так наочніше, что эквивалентно ясно(), ефект якого, буде тим же самим).

висновок, який може бути зроблений з прикладу, виглядає так:

  • поміщаючи в контейнери не об'єкти, а покажчики на них, можна помітно знизити обчислювальні витрати на маніпуляції з ними (але чи завжди є принциповим цей виграш при нинішніх обчислювальних потужностях?).

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

Тут деяку допомогу можуть надати розумні покажчики з останніх стандартів C ++ (shared_ptr или weak_ptr, але не unique_ptr і не старий добрий і проблемний auto_ptr), нам для цього в попередньому коді досить змінити 4 рядки:

У Windows для shared_ptr необхідний #include <пам'ять> , а в інших системах не обов'язково.

И поведінка додатки істотно зміниться:

16-2

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

Нові уроки з програмування:

дата
сторінка
Дороговкази в контейнерах. STL (частина 16)
рейтинг
51зірка1зірка1зірка1зірка1зірка
Olej

Про Olej

Стаж практичних програмних розробок близько 40 лет. Викладач міжнародної софтверної компанії Global Logic. Постійний автор публікацій IBM Developer Works. Науковий редактор книжкового видавництва комп'ютерної літератури "Символ-Плюс", Санкт-Петербург.

залишити коментар

Код розміщуйте в тегах: <pre class="lang:C ++ декодуванням:true ">ВАШ КОД</заздалегідь>