Перейти к содержанию

Семантика копирования и правило пяти

Начало урока

Семантика копирования и правило пяти

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

Главная идея: Любой класс C++ уже умеет копироваться, присваиваться и уничтожаться - эти операции пишет за вас компилятор. Это поведение идеально для классов из членов-значений, но опасно для класса, который владеет сырым ресурсом (памятью в куче, дескриптором файла, сокетом). Копирование по умолчанию дублирует указатель, а не то, на что он указывает, поэтому два объекта начинают владеть одним ресурсом и освобождают его дважды. Правило пяти подсказывает, когда и как взять эти операции под контроль.
К концу вы сможете:
  • назвать специальные функции-члены, которые генерирует компилятор, и сказать, что каждая из них делает по умолчанию,
  • объяснить разницу между поверхностной и глубокой копией и почему поверхностная копия владеющего класса приводит к двойному освобождению,
  • написать корректный конструктор копирования и оператор копирующего присваивания (включая идиому copy-and-swap),
  • применять правило трёх, правило пяти и правило нуля и использовать =default и =delete для управления тем, какие операции существуют.

Эта тема предполагает, что вы уже знаете сырые указатели, new/delete и RAII. Это недостающее звено, на которое незаметно опирается Введение в семантику перемещения: операции перемещения обретают смысл только после того, как вы поймёте операции копирования.

1. Специальные функции-члены

Есть небольшой набор функций-членов, которые компилятор генерирует за вас, если вы их не написали. Их называют специальными функциями-членами. Для семантики копирования сначала важны три из них:

  • Деструктор ~T() - выполняется, когда объект уничтожается; его задача - освободить то, чем объект владеет.
  • Конструктор копирования T(const T&) - строит совершенно новый объект как копию существующего (T b = a; или T b(a);).
  • Оператор копирующего присваивания T& operator=(const T&) - заменяет содержимое уже созданного объекта копией другого (b = a;).

Ещё две присоединяются к ним в современном C++ (операции перемещения, с которыми вы встретились в предыдущей теме): конструктор перемещения T(T&&) и оператор перемещающего присваивания T& operator=(T&&). Вместе эти пять - предмет правила пяти.

Сгенерированные компилятором операции копирования выполняют почленное копирование: копируют каждый член так, как он копирует себя сам. Для int это копирует значение; для сырого указателя это копирует адрес, а не память, на которую он указывает. Именно этот факт - корень всех ошибок в этой теме.

Продолжите этот урок на YourAIZone

В полном уроке — объяснение целиком, разобранные примеры, частые ошибки, тесты с мгновенной проверкой и ИИ-репетитор. Начните сразу как гость или создайте аккаунт, чтобы сохранять прогресс.

В полном уроке

  • Объяснение целиком
  • Разобранные примеры
  • Частые ошибки и как их избежать
  • Тестовые вопросы: 15
  • ИИ-репетитор, который отвечает на вопросы по теме
  • Отслеживание прогресса для ученика, родителей и учителя