← Назад ко всем вопросам

В чем разница между std::unique_ptr, std::shared_ptr и std::weak_ptr

1️⃣ Как кратко ответить

std::unique_ptr — это умный указатель, который владеет объектом эксклюзивно, не допускает копирования и автоматически освобождает память при выходе из области видимости. std::shared_ptr — это умный указатель, который позволяет нескольким указателям владеть одним объектом, используя счетчик ссылок для управления временем жизни объекта. std::weak_ptr — это вспомогательный указатель, который не влияет на счетчик ссылок std::shared_ptr, предотвращая циклические зависимости и позволяя безопасно проверять существование объекта.

2️⃣ Подробное объяснение темы

Умные указатели в C++ — это инструменты для автоматического управления памятью, которые помогают избежать утечек памяти и ошибок доступа. Они инкапсулируют обычные указатели и обеспечивают автоматическое освобождение памяти, когда объект больше не нужен. Рассмотрим три основных типа умных указателей: std::unique_ptr, std::shared_ptr и std::weak_ptr.

std::unique_ptr

std::unique_ptr — это умный указатель, который владеет объектом эксклюзивно. Это значит, что только один std::unique_ptr может владеть данным объектом в любой момент времени. Он не допускает копирования, но поддерживает перемещение, что позволяет передавать владение объектом.

#include <iostream>
#include <memory>
​
int main() {
    // Создаем std::unique_ptr, который владеет объектом типа int
    std::unique_ptr<int> uniquePtr(new int(10));
​
    // Доступ к значению через оператор разыменования
    std::cout << "Value: " << *uniquePtr << std::endl;
​
    // Передача владения другому std::unique_ptr
    std::unique_ptr<int> anotherPtr = std::move(uniquePtr);
​
    // uniquePtr теперь не владеет объектом
    if (!uniquePtr) {
        std::cout << "uniquePtr is now empty." << std::endl;
    }
​
    return 0;
}
  • std::unique_ptr<int> uniquePtr(new int(10)); — создается std::unique_ptr, который владеет объектом типа int.
  • std::cout << "Value: " << *uniquePtr << std::endl; — доступ к значению через оператор разыменования.
  • std::unique_ptr<int> anotherPtr = std::move(uniquePtr); — передача владения объектом другому std::unique_ptr с помощью std::move.
  • if (!uniquePtr) { ... } — проверка, что uniquePtr больше не владеет объектом.

std::shared_ptr

std::shared_ptr — это умный указатель, который позволяет нескольким указателям владеть одним объектом. Он использует счетчик ссылок для отслеживания количества std::shared_ptr, ссылающихся на объект. Когда счетчик ссылок достигает нуля, объект автоматически удаляется.

#include <iostream>
#include <memory>
​
int main() {
    // Создаем std::shared_ptr, который владеет объектом типа int
    std::shared_ptr<int> sharedPtr1 = std::make_shared<int>(20);
​
    // Создаем еще один std::shared_ptr, который ссылается на тот же объект
    std::shared_ptr<int> sharedPtr2 = sharedPtr1;
​
    // Выводим значение и счетчик ссылок
    std::cout << "Value: " << *sharedPtr1 << ", Use count: " << sharedPtr1.use_count() << std::endl;
​
    return 0;
}
  • std::shared_ptr<int> sharedPtr1 = std::make_shared<int>(20); — создается std::shared_ptr, который владеет объектом типа int.
  • std::shared_ptr<int> sharedPtr2 = sharedPtr1; — создается еще один std::shared_ptr, который ссылается на тот же объект.
  • std::cout << "Value: " << *sharedPtr1 << ", Use count: " << sharedPtr1.use_count() << std::endl; — вывод значения и текущего счетчика ссылок.

std::weak_ptr

std::weak_ptr — это вспомогательный указатель, который ссылается на объект, управляемый std::shared_ptr, но не увеличивает счетчик ссылок. Это позволяет избежать циклических зависимостей, которые могут привести к утечкам памяти.

#include <iostream>
#include <memory>
​
int main() {
    // Создаем std::shared_ptr, который владеет объектом типа int
    std::shared_ptr<int> sharedPtr = std::make_shared<int>(30);
​
    // Создаем std::weak_ptr, который ссылается на тот же объект
    std::weak_ptr<int> weakPtr = sharedPtr;
​
    // Проверяем, существует ли объект
    if (auto lockedPtr = weakPtr.lock()) {
        std::cout << "Value: " << *lockedPtr << std::endl;
    } else {
        std::cout << "Object no longer exists." << std::endl;
    }
​
    return 0;
}
  • std::weak_ptr<int> weakPtr = sharedPtr; — создается std::weak_ptr, который ссылается на объект, управляемый std::shared_ptr.
  • if (auto lockedPtr = weakPtr.lock()) { ... } — проверка существования объекта с помощью lock(), который возвращает std::shared_ptr, если объект существует.

Эти три типа умных указателей обеспечивают гибкость и безопасность при управлении динамической памятью в C++, помогая избежать распространенных ошибок, связанных с управлением памятью.

Тема: Умные указатели / Владение
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки