Правило трёх/пяти
Правильно управляйте копированием и перемещением
«Правило трёх/пяти» — бесплатный урок C++ Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.
Правило трёх
Если классу нужен пользовательский деструктор, ему почти всегда также нужны пользовательские конструктор копирования и оператор присваивания копированием. Эти три элемента идут вместе.
Почему именно три
Класс, управляющий необладающим ресурсом, должен определить, как этот ресурс уничтожается, копируется и присваивается. Иначе поверхностные копии, созданные компилятором, приводят к двойному освобождению.
#include <iostream>
class Bad {
int* p;
public:
Bad(int v) : p(new int(v)) {}
~Bad() { delete p; }
// default copy => two objects delete the same p!
};Пользовательский конструктор копирования
Правильный конструктор копирования выполняет глубокое копирование, выделяя собственный ресурс вместо совместного использования.
#include <iostream>
class Box {
int* p;
public:
Box(int v) : p(new int(v)) {}
Box(const Box& o) : p(new int(*o.p)) {} // deep copy
~Box() { delete p; }
int get() const { return *p; }
};
int main() {
Box a(5);
Box b = a; // independent copy
std::cout << b.get() << "\n";
}Пользовательское присваивание копированием
Присваивание копированием должно освободить старый ресурс, защититься от присваивания самому себе и создать глубокую копию нового значения.
Box& operator=(const Box& o) {
if (this != &o) { // self-assignment guard
delete p;
p = new int(*o.p);
}
return *this;
}Правило пяти
В C++11 появились операции перемещения. Если Вы определяете какую-либо из пяти операций (деструктор, конструктор копирования, присваивание копированием, конструктор перемещения, присваивание перемещением), рассмотрите возможность определить все пять.
Конструктор перемещения
Конструктор перемещения забирает ресурс у временного объекта и оставляет исходный объект пустым — это гораздо дешевле копирования.
Box(Box&& o) noexcept : p(o.p) {
o.p = nullptr; // source left empty
}Присваивание перемещением
Присваивание перемещением освобождает текущий ресурс, а затем принимает владение ресурсом источника.
Box& operator=(Box&& o) noexcept {
if (this != &o) {
delete p;
p = o.p;
o.p = nullptr;
}
return *this;
}Помечайте перемещения как noexcept
Операции перемещения следует объявлять как noexcept, чтобы такие контейнеры, как std::vector, могли безопасно использовать их при перераспределении памяти.
Правило нуля
Лучше всего вообще не владеть необработанными ресурсами. Используйте std::unique_ptr, std::vector или std::string — тогда Вам не придётся определять ни одну из пяти операций: значения по умолчанию, создаваемые компилятором, будут правильными.
#include <memory>
class Good {
std::unique_ptr<int> p; // owns the resource for you
public:
Good(int v) : p(std::make_unique<int>(v)) {}
// no destructor, no copy/move needed
};Удаление операций
Если копирование не имеет смысла, запретите его: Box(const Box&) = delete;. Так тип намеренно становится доступным только для перемещения или вообще некопируемым.
Выбор подходящего правила
Стремитесь следовать правилу нуля. Переходите к правилу пяти только тогда, когда Вы действительно оборачиваете необработанный ресурс, для которого в стандартной библиотеке нет подходящего средства.
Быстрая проверка
Проверьте, насколько хорошо Вы понимаете правило трёх/пяти.
Итоги
Вы изучили правило трёх/пяти: управление необработанным ресурсом означает согласованное определение деструктора, операций копирования и перемещения. Помечайте операции перемещения как noexcept. Лучше всего следовать правилу нуля, используя стандартные типы RAII и не определяя ни одной из этих операций.
Изучай C++ с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 51
- Уроки
- 203
Часто задаваемые вопросы
Урок «Правило трёх/пяти» бесплатный?
Да — полный текст урока «Правило трёх/пяти» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.
Чему я научусь в уроке «Правило трёх/пяти»?
Правильно управляйте копированием и перемещением Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C++ Academy?
Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Правило трёх/пяти»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C++ Academy?
Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.