Sobes.tech
Middle

Как работи shared_ptr в C++?

sobes.tech AI

Отговор от AI

shared_ptr — това е интелигентен указател, реализиращ семантиката на владение на споделен ресурс. Той съхранява указател към обекта и указател към управляващия блок.

Управляващ блок съдържа:

  • Брояч на силните препратки (reference count).
  • Брояч на слабите препратки (weak count).
  • Потребителски функтор за изтриване (deleter), ако е зададен.
  • Потребителски аллокатор, ако е зададен.
  • Указател към съхранявания обект (същото, което се съхранява в самия shared_ptr).

Принцип на работа:

  1. Създаване: При създаване на първия shared_ptr, сочещ към обект, се създава управляващият блок, броячите на препратки се инициализират: силни — 1, слаби — 0.
    std::shared_ptr<int> ptr1 = std::make_shared<int>(10); // Създава обект int и управляващ блок
    
  2. Копиране: При копиране на shared_ptr броячът на силните препратки в управляващия блок се увеличава с 1.
    std::shared_ptr<int> ptr2 = ptr1; // Увеличава брояча на силните препратки
    
  3. Присвояване: При присвояване на shared_ptr към стар ресурс, броячът на силните препратки се намалява за стария ресурс и се увеличава за новия.
    std::shared_ptr<int> ptr3;
    ptr3 = ptr1; // Намалява брояча на стария ресурс, увеличава за новия
    
  4. Премахване: При унищожаване на shared_ptr (например, излизане от обхвата) броячът на силните препратки се намалява.
    {
        std::shared_ptr<int> ptr4 = ptr1; // Увеличава брояча на силните препратки
        // ptr4 излиза от обхвата
    } // Намалява брояча на силните препратки
    
  5. Освобождаване на ресурса: Когато броячът на силните препратки достигне нула, ресурсът (обектът, към който сочи shared_ptr) се изтрива с помощта на зададения функтор за изтриване (или delete по подразбиране).
  6. Освобождаване на управляващия блок: Управляващият блок се освобождава, когато и двата брояча (силните и слабите) достигнат нула.

Предимства:

  • Автоматично управление на паметта за споделените ресурси.
  • Безопасност срещу двойно освобождаване.
  • Поддръжка на потребителски функтори за изтриване.

Недостатъци:

  • Цикличните препратки могат да доведат до изтичане на памет (решава се с weak_ptr).
  • Леко увеличение на разходите поради управляващия блок и атомарните операции с броячите.
  • Потокобезопасност на операциите с самия shared_ptr (копиране, присвояване, промяна на съхранявания указател), но не и с обекта, към който сочи.