Урок №152. Перевантаження оператора присвоювання

  Юрій  | 

  Оновл. 18 Лют 2021  | 

 107

Оператор присвоювання (=) використовується для копіювання значень з одного об’єкту в інший (вже існуючий) об’єкт.

Присвоювання vs. Конструктор копіювання

Конструктор копіювання і оператор присвоювання виконують майже ідентичну роботу: обидва копіюють значення з одного об’єкту в значення іншого об’єкту. Однак конструктор копіювання використовується при ініціалізації нових об’єктів, тоді як оператор присвоювання замінює вміст вже існуючих об’єктів. Все просто:

   Якщо новий об’єкт створений перед виконанням операції копіювання, то використовується конструктор копіювання (передача або повернення об’єктів виконуються по значенню).

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

Перевантаження оператора присвоювання

Перевантаження оператора присвоювання (=) досить-таки просте і виконується через метод класу, але є один нюанс:

Результат виконання програми:

6/7

До цього моменту все ок. Функція перевантаження operator=() повертає прихований вказівник *this, і ми можемо навіть з’єднати виконання декількох операцій присвоювання:

Самоприсвоювання

Тут вже стає цікавіше. Самоприсвоювання — це той нюанс, про який згадувалося вище. Мова C++ дозволяє виконувати самоприсвоювання:

У прикладі, наведеному вище, самоприсвоювання не призведе до зміни стану чого-небудь і буде лише марною тратою часу і ресурсів. У більшості випадків самоприсвоювання не слід виконувати взагалі.

Крім того, у випадках, коли використовується динамічне виділення пам’яті, самоприсвоювання може бути навіть небезпечним:

Запустіть програму, і ви побачите, що виведеться Anton, як і очікувалось.

Тепер замініть функцію main() на наступну:

В результаті ви отримаєте або значення-сміття, або збій.

Розглянемо, що відбувається при виконанні операції присвоювання, коли неявний і переданий в якості аргументу об’єкти є об’єктом anton. В цьому випадку m_data дорівнює str.m_data (тобто Anton). Перше, що станеться — функція перевантаження перевірить, чи є вже значенням неявного об’єкту рядок Anton. Якщо є, то відбудеться видалення цього значення, щоб не стався витік пам’яті. Тобто значення m_data неявного об’єкта видаляється, але справа в тому, що str.m_data має ту саму адресу в пам’яті (значення якої видаляється)! Це означає, що str.m_data стане “висячим” вказівником.

Пізніше, коли ми копіюватимемо дані з параметру str функції перевантаження в наш неявний об’єкт, ми звертатимемося до “висячого” вказівника str.m_data. Це призведе до того, що ми або скопіюємо дані-сміття, або спробуємо отримати доступ до пам’яті, яку наша програма більше не має в розпорядженні (відбудеться збій).

Виявлення і обробка самоприсвоювання

На щастя, ми можемо виявити виконання самоприсвоювання. Це робиться за допомогою досить простої перевірки в функції перевантаження operator=():

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

Зверніть увагу, немає необхідності виконувати перевірку на самоприсвоювання в конструкторі копіювання. Це пов’язано з тим, що конструктор копіювання викликається тільки при створенні нових об’єктів, а способу присвоїти щойно створений об’єкт самому собі, щоб викликати конструктор копіювання — немає.

Оператор присвоювання за замовчуванням

На відміну від інших операторів, компілятор автоматично надасть відкритий оператор присвоювання за замовчуванням для вашого класу при його використанні, якщо ви не надасте його самостійно. В операторі присвоювання за замовчуванням виконується почленне присвоювання (яке є аналогічним почленній ініціалізації, яка використовується в конструкторах копіювання, що надаються мовою C++ за замовчуванням).

Як і з іншими конструкторами і операторами, ви можете заборонити виконання операції присвоювання з об’єктами ваших класів, зробивши оператор присвоювання закритим або використовуючи ключове слово delete:

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

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

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

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