Sobes.tech
Middle

¿Sobre qué base varios objetos shared_ptr pueden referirse al mismo puntero?

sobes.tech AI

Respuesta de la IA

Varios objetos std::shared_ptr pueden referirse al mismo puntero gracias a la existencia de un bloque de control (control block).

El bloque de control asociado con el objeto gestionado contiene:

  • Contador de referencias fuertes (strong reference count): Se incrementa al crear un nuevo shared_ptr para el mismo objeto. Se decrementa al destruir un shared_ptr. Cuando llega a cero, el objeto (puntero) asociado se elimina.
  • Contador de referencias débiles (weak reference count): Se usa para std::weak_ptr. Se incrementa al crear un weak_ptr desde un shared_ptr. Se decrementa al destruir un weak_ptr. Cuando ambos contadores llegan a cero, se elimina el bloque de control.
  • Puntero propio al objeto gestionado: No el puntero de datos en sí, sino aquel que es gestionado por el bloque.

Cuando creas un shared_ptr a partir de otro existente (copiar, asignar-copiar), ambos comienzan a usar el mismo bloque de control, y el contador de referencias fuertes en ese bloque aumenta.

Ejemplo:

#include <memory>
#include <iostream>

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

int main() {
    // Se crea el primer shared_ptr.
    // Se crea el bloque de control y el objeto MyData.
    // Contadores strong: 1, weak: 0.
    std::shared_ptr<MyData> ptr1 = std::make_shared<MyData>(10);
    std::cout << "conteo de uso de ptr1: " << ptr1.use_count() << "\n";

    // Se crea un segundo shared_ptr a partir de ptr1.
    // Se usa el mismo bloque de control.
    // El contador fuerte aumenta a 2.
    std::shared_ptr<MyData> ptr2 = ptr1;
    std::cout << "conteo de uso de ptr1: " << ptr1.use_count() << "\n";
    std::cout << "conteo de uso de ptr2: " << ptr2.use_count() << "\n";

    // Se crea un tercer shared_ptr a partir de ptr1.
    // Se usa el mismo bloque de control.
    // El contador fuerte aumenta a 3.
    std::shared_ptr<MyData> ptr3 = ptr1;
     std::cout << "conteo de uso de ptr1: " << ptr1.use_count() << "\n";
    std::cout << "conteo de uso de ptr2: " << ptr2.use_count() << "\n";
    std::cout << "conteo de uso de ptr3: " << ptr3.use_count() << "\n";

    std::cout << "Saliendo del ámbito.\n";
    // ptr3 sale del ámbito.
    // El contador fuerte disminuye a 2.
    // ptr2 sale del ámbito.
    // El contador fuerte disminuye a 1.
    // ptr1 sale del ámbito.
    // El contador fuerte disminuye a 0.
    // El objeto MyData se destruye.
    // El bloque de control se destruye.
}

Cada objeto shared_ptr contiene su propio puntero al bloque de control y su propio puntero al objeto de datos. Al copiar un shared_ptr, se copian ambos punteros, y además se incrementa el contador de referencias fuertes en el bloque común. De esta manera, todos los shared_ptr apuntan al mismo bloque de control, que lleva la cuenta de cuántas copias poseen el recurso y determina cuándo destruir el recurso gestionado.