Укажите ошибки в следующем объявлении класса - поя...
Created on: February 2, 2026
Answered using GPT-5.2 Thinking by Chat01
Created on: February 2, 2026
Answered using GPT-5.2 Thinking by Chat01
Укажите ошибки в следующем объявлении класса - поясните ответ - это вопрос из теста по предмету современный си++, преподаватель сказал что на него почти никто не ответил правильно, при том, что в основном отвечали или "Нарушение правила пяти, нет копирующей пары конструктора и оператора и
перемещающей пары.
Копирующую пару компилятор создаст их за нас, реализовав в них прямое
копирование.
При удалении двух копий оъекта два раза вызовется деструктор и
соответственно два удаления: первый удалит ptr_, а второй при попытке
удалить кинет ошибку.
Перемещающая пара будет deleted, так как нарушается условие сделать её
defaulted (не должно быть копирующей пары, перемещающей пары и
деструктора, деструктор есть)" или "Нарушение rule of five (правило пяти) есть нетривиальное определение деструктора и нет конструкторов перемещения, операторов присваивания (копирующего и перемещающего), а раз их нет, то компилятор создаст за нас конструктор копирования и копирующий оператор присваивания в варианте default (просто копирование полей), что приведёт сначала к двойному владению, а потом, как следствие, двойное удаление.", мы действительно проходили правило пяти и думаю про него тут действительно стоит упомянуть, но думаю тут дело не только в этом, возможно мы упускаем что-то важное, внимательно проанализируй класс
Вот этот класс (по смыслу — «очень плохой unique_ptr») содержит несколько независимых проблем. “Rule of five” тут правда ключевой, но не единственный подвох.
У класса есть сырой указатель и пользовательский деструктор, который делает delete ptr_.
При этом не объявлены:
ptr_ как число).ptr_ → при разрушении будет двойной delete (UB).a = b; сначала перезатрёт a.ptr_, не удалив старый → утечка, а потом снова двойное владение → двойной delete.Это именно то, что обычно ожидают как “правильный” ответ про правило пяти — но дальше есть ещё.
operator*: возвращает T по значению вместо ссылкиcppT operator*() const { return *ptr_; }
Должно быть примерно так:
cppT& operator*() const { return *ptr_; }
(или const T& / перегрузки, но для unique_ptr обычно T& даже у const-объекта)
*p:cppdumb_ptr<int> p(new int(5)); *p = 10; // не скомпилируется, т.к. *p — временное значение
Лишние копирования (или перемещения), что может быть дорого.
Класс может стать вообще непригодным для некопируемых T:
cppdumb_ptr<std::mutex> p(new std::mutex); auto x = *p; // попытка копирования mutex → ошибка компиляции
cppstruct Base { virtual ~Base(){} }; struct Der : Base { int x; }; dumb_ptr<Base> p(new Der{}); Base b = *p; // тут будет копия Base (слайсинг), а не ссылка на Der
У нормального smart pointer’а *p — это ссылка, слайсинга нет.
explicit (опасные неявные преобразования)cppdumb_ptr(T *ptr = nullptr) : ptr_(ptr) {}
Без explicit возможны странные штуки:
T* -> dumb_ptr<T>Типичный стиль unique_ptr — explicit unique_ptr(pointer p).
delete, но не delete[]Деструктор:
cpp~dumb_ptr() { delete ptr_; }
Это нормально только для одиночного объекта, но если кто-то сделает:
cppdumb_ptr<int> p(new int[10]); // ошибка использования
то будет delete вместо delete[] → UB.
(В std::unique_ptr это решается отдельной специализацией для массивов unique_ptr<T[]>.)
operator* и operator-> никак не проверяют ptr_. Это не “ошибка компиляции”, но типичный источник UB:
cppdumb_ptr<int> p; *p; // UB p->...; // UB
У стандартных указателей так же (это не обязано проверяться), но на тестах иногда ожидают, что вы это заметите как “опасность интерфейса”.
unique_ptr-поведениеoperator* вернуть ссылку.explicit конструктор.Например:
cpptemplate <class T> class dumb_ptr { T* ptr_ = nullptr; public: explicit dumb_ptr(T* p = nullptr) noexcept : ptr_(p) {} ~dumb_ptr() { delete ptr_; } dumb_ptr(const dumb_ptr&) = delete; dumb_ptr& operator=(const dumb_ptr&) = delete; dumb_ptr(dumb_ptr&& other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; } dumb_ptr& operator=(dumb_ptr&& other) noexcept { if (this != &other) { delete ptr_; ptr_ = other.ptr_; other.ptr_ = nullptr; } return *this; } T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } };
operator* возвращает T, а не T& — из-за этого ломается модификация, появляется копирование/некопируемость/слайсинг.explicit — неявный захват владения.delete vs delete[] — опасная область использования.Если хочешь, я могу составить “шаблон правильного ответа на тест” в 5–7 строк (как его обычно хотят видеть преподаватели), но по сути самые нетривиальные пункты — это именно возврат по значению в operator* и неявные преобразования из-за отсутствия explicit.