¿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_ptrpara el mismo objeto. Se decrementa al destruir unshared_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 unweak_ptrdesde unshared_ptr. Se decrementa al destruir unweak_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.