Урок №188. Часткова спеціалізація шаблонів і Вказівники

  Юрій  | 

  Оновл. 25 Бер 2021  | 

 30

На уроці про спеціалізацію шаблону функції ми розглядали шаблон класу Repository:

Ми говорили про проблему цього шаблону при роботі з типом char*, коли виконувалося поверхневе копіювання (присвоювання вказівника) в конструкторі класу Repository. В якості рішення ми використовували повну спеціалізацію шаблону для створення спеціалізованої версії конструктора класу Repository для роботи з типом char*, в якому виділялася пам’ять і виконувалося глибоке копіювання m_value. Ось спеціалізація конструктора і деструктора класу Repository для роботи з типом char* (з матеріалів того ж уроку):

Хоча все відмінно працює з типом char*, але як щодо інших типів вказівників (наприклад, int*)? Оскільки T — це будь-який тип вказівника, то при роботі з тим же int* виконається поверхневе копіювання (що нам не потрібно), або нам доведеться дублювати вищенаведений код (спеціалізація конструктора і деструктора), але вже замість char* використовувати int*. А дублювання коду, як ми вже знаємо, не найкращий варіант!

На щастя, використовуючи часткову спеціалізацію шаблону, ми можемо визначити спеціальну версію класу Repository, яка працювала б з усіма типами вказівників (при цьому не потрібно вказувати конкретні типи вказівників):

І приклад з практики:

Результат:

6
8

При оголошенні об’єкта myintptr з типом int*, компілятор бачить, що ми раніше визначили часткову спеціалізацію шаблону класу для роботи з типами вказівників, і, враховуючи, що ми використовували тип int*, компілятор створить екземпляр часткової спеціалізації шаблону для роботи з типом вказівника. Конструктор цієї спеціалізації виконує глибоке копіювання параметру x. Пізніше, коли ми змінюємо значення x на 10, myintptr.m_value ніяк не змінюється, тому що виконалося глибоке копіювання, при якому m_value отримав свою власну копію x.

Якби цієї часткової спеціалізації не існувало, то створився б екземпляр загального шаблону класу, в якому виконалося б поверхневе копіювання, а myintptr.m_value і x вказували б на одну і ту ж адресу в пам’яті. В такому випадку, при зміні значення змінної x на 10, ми також зачепили б і значення myintptr (воно також стало б дорівнювати 10).

Варто відзначити, що, оскільки в нашій частковій спеціалізації копіюється лише одне значення, при роботі з рядками C-style копіюватися буде тільки перший символ (тому що рядок — це масив, а вказівник на масив вказує тільки на перший елемент масиву). Якщо ж потрібно повністю скопіювати рядок, то спеціалізація конструктора (і деструктора) для типу char* повинна бути повною. В такому випадку, повна спеціалізація матиме більший пріоритет, ніж часткова спеціалізація. Наприклад, ось програма, в якій використовується як часткова спеціалізація для роботи з типами вказівників, так і повна спеціалізація для роботи з типом char*:

Все працює як потрібно:

6
8
Anton

Загалом, використання часткової спеціалізації шаблону класу для роботи з типами вказівників дозволяє передбачити всі можливі варіанти використання коду на практиці.

Оцінити статтю:

1 Зірка2 Зірки3 Зірки4 Зірки5 Зірок (1 оцінок, середня: 5,00 з 5)
Loading...

Залишити відповідь

Ваш E-mail не буде опублікований. Обов'язкові поля відмічені *