Ответ
std::unique_ptr реализует исключительное владение (exclusive ownership). Ресурсом владеет ровно один unique_ptr в каждый момент времени. Копирование запрещено, перемещение — разрешено. Это легковесный указатель с нулевыми накладными расходами (по размеру и производительности сравним с сырым указателем).
std::shared_ptr реализует разделяемое владение (shared ownership) через подсчет ссылок. Ресурс уничтожается, когда удаляется последний shared_ptr, ссылающийся на него. Поддерживает копирование.
Сравнение:
| Критерий | std::unique_ptr<T> |
std::shared_ptr<T> |
|---|---|---|
| Владение | Эксклюзивное | Разделяемое |
| Накладные расходы | Минимальные (указатель) | Указатель + контрольный блок со счетчиком ссылок |
| Копирование | Запрещено | Разрешено (инкрементирует счетчик) |
| Перемещение | Разрешено (передача владения) | Разрешено |
Примеры:
// unique_ptr: фабричная функция возвращает объект, которым должен владеть только вызывающий.
std::unique_ptr<MyClass> createResource() {
return std::make_unique<MyClass>();
}
auto resource = createResource(); // Владение передано в resource
// auto resource2 = resource; // Ошибка компиляции: нельзя копировать
auto resource2 = std::move(resource); // OK: владение передано resource2, resource теперь nullptr
// shared_ptr: несколько компонентов системы используют один кэшированный ресурс.
auto cachedConfig = std::make_shared<Config>();
auto processor1 = cachedConfig; // Оба shared_ptr владеют одним объектом Config
auto processor2 = cachedConfig; // Счетчик ссылок = 3
processor1.reset(); // Счетчик ссылок = 2
// Объект Config будет уничтожен, когда выйдут из области видимости cachedConfig и processor2.
Важные замечания:
- Циклические ссылки:
shared_ptrмогут создавать циклические зависимости, приводящие к утечкам памяти. Для их разрыва используетсяstd::weak_ptr. - Правило: Всегда предпочитайте
unique_ptrкак более простой и эффективный инструмент. Используйтеshared_ptrтолько тогда, когда семантика разделяемого владения действительно необходима.