Sobes.tech
Middle

Какво знаете за умните указатели в C++?

sobes.tech AI

Отговор от AI

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

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

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

std::unique_ptr

  • Владее ресурс ексклузивно.
  • Не може да бъде копиран, но може да бъде преместван.
  • Използва се за уникално владение на ресурс.
  • Разходите са минимални, еквивалентни на суров указател.
// пример с unique_ptr
#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; // Неопределено поведение: ptr сега е празен
    return 0;
}

std::shared_ptr

  • Позволява на множество указатели да притежават един ресурс.
  • Използва брояч на препратки. Паметта се освобождава, когато броячът стане нула.
  • Може да бъде копиран. Всяко копие увеличава брояча.
  • Има по-високи разходи в сравнение с unique_ptr поради управлението на брояча.
// пример с shared_ptr
#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
#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 << "Ресурсът вече е освободен." << std::endl;
    }

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

    if (auto locked_ptr = weak_ptr_int.lock()) {
        std::cout << *locked_ptr << std::endl;
    } else {
        std::cout << "Ресурсът вече е освободен." << std::endl; // Ресурсът е освободен
    }
    return 0;
}

Използването на умни указатели е добра практика в съвременния C++, тъй като значително намалява вероятността от грешки при управлението на паметта.