Muchas respuestas abordan la forma en que se almacena el recuento de referencias (se almacena en una memoria compartida para todas las shared_ptr que contienen el mismo puntero nativo), pero la mayoría elude el problema de las fugas.
La manera más fácil de filtrar la memoria con los punteros contados de referencia es crear ciclos. Como ejemplo, una lista doblemente enlazada donde todos los punteros son shared_ptr con al menos dos elementos se garantiza que no se eliminará. Incluso si los punteros externos se liberan, los punteros internos seguirán contando, y el recuento de referencias no alcanzará 0. Es decir, al menos, con la implementación más ingenua.
La solución más fácil para el problema del ciclo es la mezcla de shared_ptr (punteros de referencia contados) con punteros débiles que no comparten la propiedad del objeto.
Los punteros compartidos compartirán tanto el recurso (puntero) como la información adicional de la referencia_cuenta. Cuando utiliza punteros débiles, el recuento de referencias se duplica: hay un recuento de referencia de puntero compartido y un recuento de referencia de puntero débil. El recurso se libera siempre que el conteo del puntero compartido llega a 0, pero la información reference_count se deja con vida hasta que se lanza el último puntero débil.
En la lista de doble enlace, la referencia externa se lleva a cabo en un shared_ptr, mientras que los enlaces internos son solo weak_ptr. Cuando no hay referencias externas (shared_ptr) se liberan los elementos de la lista, eliminando las referencias débiles. Al final, todas las referencias débiles se han eliminado y el último puntero débil de cada recurso libera la información reference_count.
Es menos confuso que el texto anterior parece ... Lo intentaré más tarde.
Esta es la respuesta más correcta. –
El enfoque de lista enlazada evita la asignación adicional, pero es muy difícil hacer "thread-safe" sin un mutex global. ("thread-safe" como en "como hilo seguro como un puntero sin formato") – curiousguy
Además, si usa 'make_shared', también puede evitar la asignación adicional colocando el objeto asignado y el contador de instancia en un solo bloque de memoria. – Ferruccio