diferencias entre el RPP compartido y el rpp débil


Estoy leyendo el libro de Scott Meyers "Effective C++". Se mencionó que hay tr1::shared_ptr y tr1::weak_ptr actúan como punteros incorporados, pero mantienen un registro de cuántos tr1::shared_ptrs apuntan a un objeto.

Esto se conoce como conteo de referencia. Esto funciona bien en la prevención de fugas de recursos en estructuras de datos acíclicas, pero si dos o más objetos contienen tr1::shared_ptrs tal que se forma un ciclo, el ciclo puede mantener el recuento de referencia del otro por encima de cero, incluso cuando todos los punteros externos al ciclo han sido destruir.

Ahí es donde tr1::weak_ptrs entran en juego.

Mi pregunta es cómo las estructuras de datos cíclicos hacen que la referencia cuente por encima de cero. Amablemente solicito un ejemplo de programa C++. ¿Cómo se resuelve el problema mediante weak_ptrs? (de nuevo, con ejemplo por favor).

Author: Logan, 2011-02-13

5 answers

A shared_ptr envuelve un mecanismo de conteo de referencia alrededor de un puntero sin procesar. Así que para cada instancia de la shared_ptr el recuento de referencia se incrementa en uno. Si dos objetos share_ptr se refieren entre sí, nunca se eliminarán porque nunca terminarán con un recuento de referencia de cero.

weak_ptr apunta a shared_ptr pero no aumenta su recuento de referencia.Esto significa que el objeto subyacente todavía se puede eliminar aunque haya una referencia weak_ptr a él.

La forma en que esto funciona es que el weak_ptr se puede usar para crear un shared_ptr para cada vez que uno quiera usar el objeto subyacente. Sin embargo, si el objeto ya ha sido eliminado, se devuelve una instancia vacía de un shared_ptr. Dado que el recuento de referencias en el objeto subyacente no aumenta con una referencia weak_ptr, una referencia circular no dará lugar a que el objeto subyacente no se elimine.

 40
Author: doron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-30 00:00:20

Permítanme repetir su pregunta: "Mi pregunta, cómo las estructuras de datos cíclicos hacen que la referencia cuente por encima de cero, amablemente solicite mostrar con ejemplo en el programa C++. Cómo se resuelve el problema con weak_ptrs de nuevo con el ejemplo por favor."

El problema ocurre con código C++ como este (conceptualmente):

class A { shared_ptr<B> b; ... };
class B { shared_ptr<A> a; ... };
shared_ptr<A> x(new A);  // +1
x->b = new B;            // +1
x->b->a = x;             // +1
// Ref count of 'x' is 2.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, there will be a memory leak:
// 2 is decremented to 1, and so both ref counts will be 1.
// (Memory is deallocated only when ref count drops to 0)

Para responder a la segunda parte de su pregunta: Es matemáticamente imposible que el conteo de referencias trate con ciclos. Por lo tanto, un weak_ptr (que es básicamente sólo un despojado versión de shared_ptr) no se puede usar para resolver el problema del ciclo - el programador está resolviendo el problema del ciclo.

Para resolverlo, el programador necesita ser consciente de la relación de propiedad entre los objetos, o necesita inventar una relación de propiedad si dicha propiedad no existe naturalmente.

El código C++ anterior se puede cambiar para que A posea B:

class A { shared_ptr<B> b; ... };
class B { weak_ptr<A>   a; ... };
shared_ptr<A> x(new A); // +1
x->b = new B;           // +1
x->b->a = x;            // No +1 here
// Ref count of 'x' is 1.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, its ref count will drop to 0.
// While destroying it, ref count of 'x->b' will drop to 0.
// So both A and B will be deallocated.

Una pregunta crucial es: Puede weak_ptr ser utilizado en caso de que el programador no puede decir la propiedad relación y no puede establecer ninguna propiedad estática debido a la falta de privilegios o la falta de información?

La respuesta es: Si la propiedad entre objetos no está clara, weak_ptr no puede ayudar. Si hay un ciclo, el programador tiene que encontrarlo y romperlo. Un remedio alternativo es usar un lenguaje de programación con recolección de basura completa (como: Java, C#, Go, Haskell), o usar un recolector de basura conservador (=imperfecto) que funcione con C/C++ (como: Boehm GC).

 99
Author: Frank,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-11 06:30:29

Para futuros lectores.
Solo quiero señalar que la explicación dada por Atom es excelente, aquí está el código de trabajo

#include <memory> // and others
using namespace std;

    class B; // forward declaration 
    // for clarity, add explicit destructor to see that they are not called
    class A { public: shared_ptr<B> b; ~A() {cout << "~A()" << endl; } };  
    class B { public: shared_ptr<A> a; ~B() {cout << "~B()" << endl; } };     
    shared_ptr<A> x(new A);  //x->b share_ptr is default initialized
    x->b = make_shared<B>(); // you can't do "= new B" on shared_ptr                      
    x->b->a = x;
    cout << x.use_count() << endl;  
 15
Author: newprint,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-20 04:26:00

Los punteros débiles solo "observan" el objeto administrado; no "lo mantienen vivo" ni afectan su vida útil. A diferencia de shared_ptr, cuando el último weak_ptr sale del ámbito de aplicación o desaparece, el objeto apuntado todavía puede existir porque el weak_ptr no afecta la vida útil del objeto: no tiene derechos de propiedad. El weak_ptr se puede utilizar para determinar si el objeto existe, y para proporcionar un shared_ptr que se puede utilizar para referirse a él.

La definición de weak_ptr está diseñada para hacerla relativamente infalible, por lo que como resultado hay muy poco que se puede hacer directamente con un weak_ptr. Por ejemplo, no puedes desreferenciarlo; ni operator* ni operator-> están definidos para un weak_ptr. No puede acceder al puntero al objeto con él-no hay función get(). Hay una función de comparación definida para que pueda almacenar weak_ptrs en un contenedor ordenado, pero eso es todo.

 4
Author: peterDriscoll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-05 15:39:02

Todas las respuestas anteriores son ERRÓNEAS. weak_ptr NO se usa para romper referencias cíclicas, tienen otro propósito.

Básicamente, si todos shared_ptr(s) fueron creados por llamadas make_shared() o allocate_shared(), nunca necesitará weak_ptr si no tiene otro recurso que la memoria para administrar. Estas funciones crean el objeto contador de referencia shared_ptr con el objeto en sí, y la memoria se liberará al mismo tiempo.

La única diferencia entre weak_ptr y shared_ptr es que el weak_ptr permite la referencia contador objeto que se mantendrá después de que el objeto real fue liberado. Como resultado, si mantiene una gran cantidad de shared_ptr en un std::set los objetos reales ocuparán una gran cantidad de memoria si son lo suficientemente grandes. Este problema se puede resolver usando weak_ptr en su lugar. En este caso, debe asegurarse de que el weak_ptr almacenado en el contenedor no haya caducado antes de usarlo.

 -5
Author: Earth Engine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-18 17:36:41