Sobes.tech
Middle

На каква основа няколко обекта shared_ptr могат да се позовават на един и същ указател?

sobes.tech AI

Отговор от AI

Няколко обекта std::shared_ptr могат да се позовават на един и същи указател благодарение на наличието на контролен блок (control block).

Контролният блок, свързан с управлявания обект, съдържа:

  • Брояч на силните препратки (strong reference count): Увеличава се при създаване на нов shared_ptr за същия обект. Намалява се при унищожаване на shared_ptr. Когато достигне нула, свързаният обект (указателят) се премахва.
  • Брояч на слабите препратки (weak reference count): Използва се за std::weak_ptr. Увеличава се при създаване на weak_ptr от shared_ptr. Намалява се при унищожаване на weak_ptr. Когато и двата брояча станат нула, контролният блок се премахва.
  • Собствен указател към управлявания обект: Не самият указател към данните, а този, който се управлява от блока.

Когато създавате shared_ptr от съществуващ shared_ptr (копиране, присвояване чрез копиране), те започват да използват един и същ контролен блок, и броячът на силните препратки в този блок се увеличава.

Пример:

#include <memory>
#include <iostream>

struct MyData {
    int value;
    MyData(int v) : value(v) { std::cout << "MyData(" << value << ") created.\n"; }
    ~MyData() { std::cout << "MyData(" << value << ") destroyed.\n"; }
};

int main() {
    // Създаване на първия shared_ptr.
    // Създава се контролен блок и обект MyData.
    // Брояч на силни: 1, слаб: 0.
    std::shared_ptr<MyData> ptr1 = std::make_shared<MyData>(10);
    std::cout << "ptr1 use count: " << ptr1.use_count() << "\n";

    // Създаване на втори shared_ptr от ptr1.
    // Използва същия контролен блок.
    // Броячът на силните се увеличава до 2.
    std::shared_ptr<MyData> ptr2 = ptr1;
    std::cout << "ptr1 use count: " << ptr1.use_count() << "\n";
    std::cout << "ptr2 use count: " << ptr2.use_count() << "\n";

    // Създаване на трети shared_ptr от ptr1.
    // Използва същия контролен блок.
    // Броячът на силните се увеличава до 3.
    std::shared_ptr<MyData> ptr3 = ptr1;
     std::cout << "ptr1 use count: " << ptr1.use_count() << "\n";
    std::cout << "ptr2 use count: " << ptr2.use_count() << "\n";
    std::cout << "ptr3 use count: " << ptr3.use_count() << "\n";

    std::cout << "Изход от обхвата.\n";
    // ptr3 напуска обхвата.
    // Броячът на силните намалява до 2.
    // ptr2 напуска обхвата.
    // Броячът на силните намалява до 1.
    // ptr1 напуска обхвата.
    // Броячът на силните намалява до 0.
    // Обектът MyData се унищожава.
    // Контролният блок се премахва.
}

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