Sobes.tech
Middle

Com base no que vários objetos shared_ptr podem referenciar o mesmo ponteiro?

sobes.tech IA

Resposta da IA

Vários objetos std::shared_ptr podem referir-se ao mesmo ponteiro graças à existência de um bloco de controlo (control block).

O bloco de controlo associado ao objeto gerido contém:

  • Contador de referências fortes (strong reference count): Aumenta ao criar um novo shared_ptr para o mesmo objeto. Diminui ao destruir um shared_ptr. Quando chega a zero, o objeto (ponteiro) associado é eliminado.
  • Contador de referências fracas (weak reference count): Usado para std::weak_ptr. Aumenta ao criar um weak_ptr a partir de um shared_ptr. Diminui ao destruir um weak_ptr. Quando ambos os contadores atingem zero, o bloco de controlo é eliminado.
  • Ponteiro próprio para o objeto gerido: Não o ponteiro de dados em si, mas aquele que é gerido pelo bloco.

Quando cria um shared_ptr a partir de outro existente (cópia, atribuição-cópia), ambos começam a usar o mesmo bloco de controlo, e o contador de referências fortes nesse bloco aumenta.

Exemplo:

#include <memory>
#include <iostream>

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

int main() {
    // Cria o primeiro shared_ptr.
    // Cria o bloco de controlo e o objeto MyData.
    // Contadores strong: 1, weak: 0.
    std::shared_ptr<MyData> ptr1 = std::make_shared<MyData>(10);
    std::cout << "contagem de uso de ptr1: " << ptr1.use_count() << "\n";

    // Cria um segundo shared_ptr a partir de ptr1.
    // Usa o mesmo bloco de controlo.
    // O contador strong aumenta para 2.
    std::shared_ptr<MyData> ptr2 = ptr1;
    std::cout << "contagem de uso de ptr1: " << ptr1.use_count() << "\n";
    std::cout << "contagem de uso de ptr2: " << ptr2.use_count() << "\n";

    // Cria um terceiro shared_ptr a partir de ptr1.
    // Usa o mesmo bloco de controlo.
    // O contador strong aumenta para 3.
    std::shared_ptr<MyData> ptr3 = ptr1;
     std::cout << "contagem de uso de ptr1: " << ptr1.use_count() << "\n";
    std::cout << "contagem de uso de ptr2: " << ptr2.use_count() << "\n";
    std::cout << "contagem de uso de ptr3: " << ptr3.use_count() << "\n";

    std::cout << "Sair do escopo.\n";
    // ptr3 sai do escopo.
    // O contador strong diminui para 2.
    // ptr2 sai do escopo.
    // O contador strong diminui para 1.
    // ptr1 sai do escopo.
    // O contador strong diminui para 0.
    // O objeto MyData é destruído.
    // O bloco de controlo é destruído.
}

Cada objeto shared_ptr contém o seu próprio ponteiro para o bloco de controlo e o seu próprio ponteiro para o objeto de dados. Ao copiar um shared_ptr, ambos os ponteiros são copiados, e o contador de referências fortes no bloco comum é incrementado. Assim, todos os shared_ptr apontam para o mesmo bloco de controlo, que acompanha o número de cópias que possuem o recurso e determina o momento de destruição do recurso gerido.