В каких случаях unique_ptr предпочтительнее shared_ptr
Что проверяют
Думаете ли вы о владении, а не только о том, чтобы память не текла. Правильная позиция: unique_ptr выбор по умолчанию, shared_ptr берут, когда владельцев действительно несколько. Следом спрашивают, во что обходится shared_ptr и как передавать умные указатели в функции.
Как отвечать
Начните с правила R.21 из C++ Core Guidelines: предпочитайте unique_ptr, если разделяемое владение не нужно. Дальше аргументы:
- стоимость:
unique_ptrс deleter по умолчанию на практике размером с сырой указатель, а перемещение сводится к копированию адреса.shared_ptrхранит два указателя, выделяет control block и меняет счётчик атомарной операцией на каждой копии; - ясность: тип сразу говорит, кто удаляет объект. С
shared_ptrвремя жизни размазано по коду, объект живёт, пока хоть кто-то держит копию; - гибкость:
unique_ptrв любой момент превращается вshared_ptrчерезstd::move, обратно нельзя. Поэтому фабрики возвращаютunique_ptr; - типичные места: pimpl, владение ресурсом внутри класса,
std::vector<std::unique_ptr<Base>>для полиморфных объектов, передача владения в функцию-приёмник.
shared_ptr оправдан, когда время жизни определяют несколько независимых участников: кэш, который раздаёт объекты и следит за ними через weak_ptr, или асинхронный колбэк, который продлевает жизнь объекта через shared_from_this().
Про параметры функций: если функция только пользуется объектом, принимайте T& или T*, а не умный указатель. unique_ptr по значению означает «забираю владение», shared_ptr по значению означает «становлюсь совладельцем».
Где спотыкаются
Говорят, что unique_ptr передаётся по значению как обычная переменная. Он только перемещаемый, копирование запрещено, и без std::move код не скомпилируется.
Передают shared_ptr по значению во все функции подряд. Каждый вызов это атомарный инкремент и декремент, в горячем цикле это заметно.
Делают pimpl на unique_ptr и получают ошибку компиляции про неполный тип. Деструктор внешнего класса нужно определить в .cpp, где тип реализации уже полный.