Урок 144. Перегрузка оператора присваивания

   ⁄ 

 Обновлено 15 мая 2018  ⁄ 

 ⁄   2 

⁄   170

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

Присваивание 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=:

Проверяя, является ли наш неявный объект тем же, что и передаваемый в качестве параметра, мы сможем сразу же возвратить его, без выполнения какого-либо кода.

Обратите внимание, нет необходимости выполнять проверку на самоприсваивание в конструкторе копирования. Это связано с тем, что конструктор копирования вызывается только при создании новых объектов, а способа присвоить только что созданный объект самому себе, чтобы вызвать конструктор копирования — нет.

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

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

Как и с другими конструкторами и операторами, вы можете запретить выполнение операции присваивания с объектами ваших классов, сделав оператор присваивания закрытым или используя ключевое слово delete:

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (2 оценок, среднее: 5,00 из 5)
Загрузка...
Подписаться на обновления:

Комментариев: 2

  1. Герман:

    Спасибо за огромный труд, с нетерпением жду следующих уроков!!!!!

    1. Юрий:

      Спасибо, что читаете 🙂

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

ПОДПИСЫВАЙТЕСЬ

НА КАНАЛ RAVESLI В TELEGRAM

@ravesli

ПОДПИСАТЬСЯ БЕСПЛАТНО