Как защитить объект от копирования в C++, какие есть способы
Что проверяют
Знаете ли вы, как запрет копирования взаимодействует с правилом пяти, и чем способ из C++11 лучше приёма из C++03. Следом спрашивают, что станет с перемещением, если удалить копирование, и почему член типа std::unique_ptr делает класс некопируемым.
Как отвечать
Назовите способы по порядку появления:
= delete:Foo(const Foo&) = delete;иFoo& operator=(const Foo&) = delete;. Ошибка при компиляции, в том числе внутри класса и у друзей. Удалённые функции принято объявлятьpublic, тогда компилятор пишет «функция удалена», а не «функция недоступна»;- приватные объявления без определения: приём до C++11. Внешний код получает ошибку доступа, а члены и друзья класса только ошибку линковки;
- базовый класс:
boost::noncopyableили свой аналог, сегодня его заменяют две строки с= delete; - некопируемый член: если в классе есть
std::unique_ptr,std::mutexилиstd::thread, неявные копирующие операции определяются как удалённые. Это правило нуля: класс ничего не объявляет, но копировать его нельзя. Сunique_ptrперемещение продолжает работать, сstd::mutexкласс не перемещается вовсе.
Главная тонкость: если вы объявили копирующий конструктор, пусть даже как = delete, компилятор не генерирует неявные перемещающие операции. Rvalue попадает в удалённый копирующий конструктор, и класс перестаёт перемещаться. Для типа «только перемещение» нужно явно написать Foo(Foo&&) noexcept = default; и Foo& operator=(Foo&&) noexcept = default;.
Плюсом будет упомянуть C++17: гарантированный пропуск копирования позволяет вернуть из фабрики даже неперемещаемый объект через return Foo{...};.
Где спотыкаются
Удаляют только копирующий конструктор и забывают оператор присваивания. Неявный копирующий operator= при этом всё ещё генерируется (поведение устаревшее, но рабочее), и a = b; компилируется.
Удивляются, что после запрета копирования перестал компилироваться v.push_back(std::move(x)). Перемещающие операции просто не были объявлены.
Называют семантику перемещения способом защиты от копирования. Перемещение лишь даёт альтернативу и копирование само по себе не запрещает.