Ответ
std::unique_ptr реализует семантику исключительного владения ресурсом. Поэтому разрешена только операция перемещающего присваивания. Копирующее присваивание и конструктор копирования явно удалены.
Разрешенные сценарии:
-
Присваивание из временного объекта (rvalue) с помощью
std::move:std::unique_ptr<int> ptr1 = std::make_unique<int>(42); std::unique_ptr<int> ptr2; ptr2 = std::move(ptr1); // OK: владение передается от ptr1 к ptr2 // Теперь ptr1 == nullptr, ptr2 владеет int(42) -
Присваивание результата
std::make_uniqueили другой фабричной функции:std::unique_ptr<MyClass> ptr; ptr = std::make_unique<MyClass>(); // OK: перемещение из временного объекта
Запрещенные сценарии:
std::unique_ptr<int> a = std::make_unique<int>(5);
std::unique_ptr<int> b = a; // Ошибка компиляции: конструктор копирования удален
b = a; // Ошибка компиляции: оператор копирующего присваивания удален
Это гарантирует, что в любой момент времени только один unique_ptr владеет конкретным динамическим объектом, что предотвращает двойное удаление и упрощает рассуждение о владении.
Ответ 18+ 🔞
А, ну ты про этот твой unique_ptr спрашиваешь? Ну, слушай, история-то проще пареной репы, если разобраться. Представь себе, что у тебя есть одна конкретная, едрид-мадрид, кружка. И ты — её единственный и неповторимый владелец. Ты можешь её кому-то отдать (ну, типа, сунуть в руки и забыть), но ты не можешь её скопировать волшебным образом, чтобы у тебя и у соседа была одна и та же физическая кружка. Так вот std::unique_ptr — это и есть та самая кружка, только для кусков памяти в хипе. Владение исключительное, блядь, один хозяин.
Поэтому с ним можно делать только одно — перемещать. Как будто ты говоришь: «На, держи, это теперь твоя головная боль». Исходный указатель после этого становится пустым, нихуя не указывает. Это и есть операция перемещающего присваивания.
Что работает (и это окей):
-
Передал владение другому с помощью
std::move(типа «на, забирай, мне похуй»):std::unique_ptr<int> ptr1 = std::make_unique<int>(42); std::unique_ptr<int> ptr2; ptr2 = std::move(ptr1); // Всё норм, владение переехало от ptr1 к ptr2 // Теперь ptr1 — пустой, как твои обещания в понедельник, а ptr2 владеет этой памятью. -
Присвоил прямо результат создания (
make_unique), это же временный объект, его и так скоро удалят:std::unique_ptr<MyClass> ptr; ptr = std::make_unique<MyClass>(); // Окей, создали и сразу передали тебе.
Что НЕ работает (и щас получишь по шапке от компилятора):
std::unique_ptr<int> a = std::make_unique<int>(5);
std::unique_ptr<int> b = a; // Ошибка компиляции: ёпта, ты чё, клонировать собрался? Конструктор копирования удалён!
b = a; // Ошибка компиляции: опять? Оператор копирующего присваивания тоже удалён, я же сказал!
Весь смысл в этом и заключается, чувак. Чтобы в любой момент времени было ясно, какого хуя и кто отвечает за удаление объекта. Никаких двойных удалений, когда два дурака пытаются освободить одну память, никакой путаницы. Один владелец — одна ответственность. Красота, ёпта.