El mundo en el que vive Bjarne es muy ... académico, por falta de un término mejor. Si su código puede diseñarse y estructurarse de manera tal que los objetos tengan jerarquías relacionales muy deliberadas, de manera que las relaciones de propiedad sean rígidas e inflexibles, el código fluye en una dirección (desde un nivel alto hasta un nivel bajo) y los objetos solo hablan con los que están más abajo. la jerarquía, entonces no encontrará mucha necesidad de shared_ptr
. Es algo que se usa en esas raras ocasiones en que alguien tiene que romper las reglas. Pero de lo contrario, puede pegar todo en vector
s u otras estructuras de datos que utilizan valores semánticos, y unique_ptr
s para las cosas que tiene que asignar por separado.
Si bien es un gran mundo para vivir, no es lo que haces todo el tiempo. Si no puede organizar su código de esa manera, ya que el diseño del sistema que está tratando de hacer significa que es imposible (o simplemente muy desagradable), entonces encontrará que necesita propiedad compartida de objetos cada vez más.
En un sistema de este tipo, mantener los punteros desnudos no es ... exactamente peligroso, pero sí plantea preguntas. Lo mejor de shared_ptr
es que proporciona garantías sintácticas razonables sobre la vida útil del objeto. ¿Se puede romper? Por supuesto. Pero la gente también puede const_cast
cosas; la atención básica y la alimentación de shared_ptr
deben proporcionar una calidad de vida razonable para los objetos asignados, cuya propiedad se debe compartir.
Luego, hay weak_ptr
s, que no se puede usar en ausencia de un shared_ptr
. Si su sistema está rígidamente estructurado, entonces puede almacenar un puntero desnudo en algún objeto, con la certeza de que la estructura de la aplicación garantiza que el objeto al que apunta lo sobrevivirá. Puede llamar a una función que devuelve un puntero a algún valor interno o externo (por ejemplo, busque un objeto llamado X). En un código estructurado correctamente, esa función solo estaría disponible si la vida útil del objeto fuera superior a la suya; por lo tanto, almacenar ese puntero desnudo en su objeto está bien.
Dado que no siempre es posible lograr la rigidez en sistemas reales, necesita alguna forma de garantizar razonablemente la vida útil. A veces, no necesitas la propiedad completa; a veces, solo necesitas saber cuándo el puntero es bueno o malo. Ahí es donde entra weak_ptr
. Ha habido casos en los que podría haber usado unique_ptr
o boost::scoped_ptr
, pero tuve que usar shared_ptr
porque específicamente necesitaba dar a alguien un puntero "volátil". Un puntero cuya vida útil era indeterminada, y podían consultar cuándo se destruyó ese puntero.
Una forma segura de sobrevivir cuando el estado del mundo es indeterminado.
¿Se podría haber hecho con alguna llamada de función para obtener el puntero, en lugar de a través de weak_ptr
? Sí, pero eso podría romperse más fácilmente. Una función que devuelve un puntero desnudo no tiene manera de sugerir de manera sintáctica que el usuario no haga algo como almacenar ese puntero a largo plazo. Devolver un shared_ptr
también hace que sea demasiado fácil para alguien simplemente almacenarlo y potencialmente prolongar la vida útil de un objeto. Sin embargo, devolver un weak_ptr
sugiere fuertemente que almacenar el shared_ptr
que obtiene de lock
es una ... idea dudosa. No le impedirá que lo haga, pero nada en C ++ le impide romper el código. weak_ptr
proporciona cierta resistencia mínima al hacer lo natural.
Ahora, eso no quiere decir que shared_ptr
no pueda ser usado en exceso ; ciertamente puede Especialmente antes de unique_ptr
, hubo muchos casos en los que simplemente usé boost::shared_ptr
porque necesitaba pasar un puntero RAII o ponerlo en una lista. Sin mover la semántica y unique_ptr
, boost::shared_ptr
fue la única solución real.
Y puedes usarlo en lugares donde no sea necesario. Como se indicó anteriormente, la estructura de código adecuada puede eliminar la necesidad de algunos usos de shared_ptr
. Pero si su sistema no se puede estructurar como tal y aún hace lo que necesita, shared_ptr
será de gran utilidad.