template
inline Type * MP
Отже, після невеликого підігріву розумні покажчики перетворилися в ведучі. Тепер в нашому вариві з'являється ще один інгредієнт - дескриптори (handles) C ++. Не плутайте цей термін з дескрипторами, використовуваними в операційних системах Macintosh і Windows. Деяка схожість існує, але ідіома дескрипторів C ++ має власну унікальну семантику і набір правил.
Основна ідея полягає в тому, щоб використовувати розумні покажчики для посилань на провідні покажчики. Ці додаткові покажчики і називаються дескрипторами. Основа, на якій ми будемо будувати клас дескрипторів, в першому наближенні виглядає так:
template
MP
Безаргументний конструктор Н створює новий ведучий покажчик. Цей провідний покажчик, в свою чергу, створює вказується об'єкт. Існує другий конструктор, який отримує провідний покажчик і ініціалізує їм змінну ptr. Конструктор копій і оператор = за замовчуванням годяться, оскільки будь-якому провідному вказівником може відповідати кілька дескрипторів. Робота оператора -> заснована на рекурсивном алгоритмі, використовуваному компілятором: оператор -> дескриптора повертає провідний покажчик; потім оператор -> ведучого покажчика повертає покажчик Type * який є одним з базових типів компілятора.
Наведене рішення не назвеш витонченим - вкладені шаблони породжують плутанину, до того ж зовсім незрозуміло, коли і як видаляти провідні покажчики. Крім того, слід дозволити користувачеві безпосередньо створювати і знищувати провідні покажчики або ж укласти їх усередині дескрипторів так, як ми уклали вказуються об'єкти всередині провідних покажчиків? Невже ми працювали над вирішенням цих проблем для вказуються об'єктів лише потім, щоб зіткнутися з ними знову для провідних покажчиків? Терпіння - свого часу ми знайдемо відповідь на ці та багато інших питань.
Що ж виходить?
Ми почнемо з простого прикладу провідних покажчиків і вдосконалюємо його до рівня, який задовольнив би і більш вимогливу аудиторію. На цій стадії ще важко зрозуміти всю користь дескрипторів, але в наступних розділах вони будуть грати дуже важливу роль.
підрахунок об'єктів
Припустимо, ви хочете стежити за кількістю створених або перебувають в пам'яті об'єктів деякого класу. Одне з можливих рішень - зберігати ці відомості в статичних змінних самого класу.
class CountedStuff static int current; public: CountedStuff () <> // Не змінювати лічильник для присвоювання З цим прикладом ще можна повозитися і поліпшити його, але як би ви не старалися, доведеться змінювати код цільового класу - хоча б для того, щоб змусити його наслідувати від нашого класу. Тепер припустимо, що вказується об'єкт входить в комерційну бібліотеку. Прикро, так? Будь-які зміни небажані, а швидше за все, просто неможливі. Але ось на сцену виходить клас провідного покажчика. template static int current; Type * ptr; CMP (const CMP if (this! = cmp) ptr = new Type (* (cmp.ptr)); Тепер ведучий покажчик виконує всі підрахунки за вас. Він не потребує внесення змін до класу зазначених вище об'єкта. Цей шаблон може використовуватися для будь-якого класу за умови, що вам вдасться втиснути провідні покажчики між клієнтом і вказуються об'єктом. Навіть якщо ви не заперечуєте проти модифікації вихідного класу зазначених вище об'єкта, забезпечити такий рівень модульності без провідних покажчиків було б вкрай складно (наприклад, якби ви спробували діяти через базовий клас, то в результаті отримали б одну статичну змінну current на всі похідні класи). Цей приклад тривіальний, але навіть він демонструє важливий принцип програмування на C ++, справедливість якого згодом стає очевидною: користуйтеся розумними покажчиками, навіть якщо спочатку здається, що вони не потрібні. Якщо програма написана для розумних покажчиків, всі зміни вносяться легко і швидко. Якщо ж вам доведеться переробляти готову програму і замінювати всі оператори * розумними покажчиками, приготуйтеся до нічних чувань. У розділі 14 варіації на тему підрахунку будуть використані для реалізації простої, але в той же час потужної схеми управління пам'яттю - збирання сміття з підрахунком посилань. Припустимо, ви хочете зробити так, щоб деякий об'єкт ніколи не оновлювався (або, по крайней мере, не оновлювався звичайними клієнтами). Це завдання легко вирішується за допомогою провідних покажчиків - достатньо зробити операційну функцію operator -> () константної функцією класу. template ROMP Указується об'єкт замкнений так надійно, що до нього не добереться навіть ЦРУ. В принципі, те ж саме можна було зробити за допомогою більш простих розумних покажчиків, але провідні покажчики забезпечують стовідсотковий захист, так як клієнт ніколи не отримує прямого доступу до що вказується об'єкту. У багатьох ситуаціях існує оптимальне представлення об'єкта, яке дійсно лише для операцій читання. Якщо клієнт хоче змінити об'єкт, уявлення доводиться змінювати. Це було б легко зробити при наявності двох перевантажених версій оператора ->. одна з яких повертає Foo *. а інша - const Foo *. На жаль, різні повертаються типи не забезпечують унікальність сигнатур, тому при спробі оголосити два оператора -> компілятор від душі посміється. Програмісту доведеться заздалегідь викликати функцію, яка здійснює перехід від одного представлення до іншого. Одне з можливих застосувань цієї схеми - розподілені об'єкти. Якщо копії об'єкта не оновлюються локальними клієнтами, вони можуть бути розкидані по всій мережі. Зовсім інша справа - координація оновлень декількох екземплярів. Можна встановити правило, згідно з яким допускається існування будь-якої кількості копій тільки для читання, але лише одна головна копія. Щоб оновити об'єкт, необхідно попередньо отримати головну копію у її поточного власника. Звичайно, доводиться враховувати багато нюансів (зокрема, процедуру зміни власника головної копії), проте правильне застосування провідних покажчиків дозволяє реалізувати цю концепцію на подив просто і непомітно для клієнтів.Покажчики тільки для читання
Покажчики для читання / запису