Назад к вопросам
Middle
98
questionbank

Что вы знаете об умных указателях в C++?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Умные указатели - это RAII-обертки над обычными (сырыми) указателями в C++, предоставляющие автоматическое управление временем жизни выделенной памяти, предотвращая утечки.

Основные типы умных указателей в стандартной библиотеке C++:

  • std::unique_ptr
  • std::shared_ptr
  • std::weak_ptr

std::unique_ptr

  • Владеет ресурсом эксклюзивно.
  • Не может быть скопирован, но может быть перемещен.
  • Используется для уникального владения ресурсом.
  • Накладные расходы минимальны, эквивалентны сырому указателю.
// unique_ptr example
#include <memory>
#include <iostream>

int main() {
    std::unique_ptr<int> ptr = std::make_unique<int>(10);
    std::cout << *ptr << std::endl; // 10
    // std::unique_ptr<int> ptr2 = ptr; // Ошибка компиляции: unique_ptr не копируется
    std::unique_ptr<int> ptr3 = std::move(ptr); // Перемещение владения
    std::cout << *ptr3 << std::endl; // 10
    // std::cout << *ptr << std::endl; // Undefined behavior: ptr теперь пустой
    return 0;
}

std::shared_ptr

  • Позволяет множеству указателей совместно владеть одним ресурсом.
  • Использует счетчик ссылок (reference count). Память освобождается, когда счетчик ссылок становится равен нулю.
  • Может быть скопирован. Каждая копия увеличивает счетчик ссылок.
  • Имеет более высокие накладные расходы по сравнению с unique_ptr из-за необходимости обслуживать счетчик ссылок.
// shared_ptr example
#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>(20);
    std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 1)
    std::shared_ptr<int> ptr2 = ptr1; // Копирование, увеличивает use_count
    std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 2)
    std::shared_ptr<int> ptr3 = ptr1; // Еще одна копия
    std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 3)
    return 0;
}

std::weak_ptr

  • Не владеет ресурсом и не увеличивает счетчик ссылок.
  • Используется для решения проблемы цикличных ссылок между shared_ptr.
  • Позволяет получить доступ к ресурсу, на который указывает shared_ptr, но не предотвращает его удаление.
  • Для доступа к ресурсу необходимо преобразовать weak_ptr в shared_ptr с помощью метода lock().
// weak_ptr example
#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<int> shared_ptr_int = std::make_shared<int>(30);
    std::weak_ptr<int> weak_ptr_int = shared_ptr_int;

    if (auto locked_ptr = weak_ptr_int.lock()) {
        std::cout << *locked_ptr << std::endl; // 30
    } else {
        std::cout << "Resource has been released." << std::endl;
    }

    shared_ptr_int.reset(); // Ресурс освобождается

    if (auto locked_ptr = weak_ptr_int.lock()) {
        std::cout << *locked_ptr << std::endl;
    } else {
        std::cout << "Resource has been released." << std::endl; // Resource has been released.
    }
    return 0;
}

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