¿Debo pasar un RPP compartido por referencia? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

¿Cuáles son las mejores prácticas para pasar un shared_ptr?

Actualmente paso argumentos de función shared_ptr de la siguiente manera:

void function1( shared_ptr<TYPE>& value );
Author: mindless.panda, 2011-12-05

3 answers

En circunstancias controladas puede pasar el puntero compartido por referencia constante. Asegúrese de que nadie está borrando el objeto simultáneamente, aunque esto no debería ser demasiado difícil si tiene cuidado con a quién le da referencias.

En general, debe pasar el puntero compartido como una copia recta . Esto le da su semántica prevista: Cada ámbito que contiene una copia del puntero compartido mantiene vivo el objeto en virtud de su "compartir" en el propiedad.

La única razón para no pasar siempre por valor es que copiar un puntero compartido tiene un precio determinado debido a la actualización del recuento de referencias atómicas; sin embargo, esto podría no ser una preocupación importante.


Digresión opcional:

Dado que la pregunta principal ha sido respondida, tal vez sea instructivo considerar algunas maneras en las que debería nunca usar un puntero compartido. Aquí hay un pequeño experimento mental. Definamos un espacio compartido tipo de puntero SF = std::shared_ptr<Foo>. Para considerar las referencias, en lugar de pasar argumentos de función, veamos el tipo RSF = std::reference_wrapper<T>. Es decir, si tenemos un puntero compartido SF p(std::make_shared<Foo>());, entonces podemos hacer una envoltura de referencia con semántica de valores a través de RSF w = std::ref(p);. Demasiado para la configuración.

Ahora, todo el mundo sabe que los contenedores de punteros son campos minados. Así que std::vector<Foo*> será una pesadilla para mantener, y cualquier número de errores surgen de la gestión inadecuada de la vida. Lo que es peor conceptualmente es que nunca está claro quién posee los objetos cuyos punteros almacena el contenedor. Los punteros incluso podrían ser una mezcla de punteros a objetos dinámicos, objetos automáticos y basura. Nadie lo sabe. Así que la solución estándar es usar std::vector<SF> en su lugar. Esta es La Forma Correcta de usar el puntero compartido. Por otro lado, lo que nunca debes usar es std::vector<RSF> this ¡este es un monstruo inmanejable que en realidad es muy similar al vector original de los punteros desnudos! Por ejemplo, no está claro si el objeto al que mantener una referencia sigue vivo. Tomar una referencia del puntero compartido ha derrotado todo su propósito.

Para un segundo ejemplo, supongamos que tenemos un puntero compartido SF p como antes. Ahora tenemos una función int foo(SF) que queremos ejecutar simultáneamente. El std::thread(foo, p) habitual funciona bien, ya que el constructor de subprocesos hace una copia de sus argumentos. Sin embargo, si hubiéramos dicho std::thread(foo, std::ref(p)), estaríamos en todo tipo de problemas: El puntero compartido en el ámbito de llamada podría caducar y destruir el objeto, ¡y te quedarías con una referencia colgando y un puntero inválido!

Espero que estos dos ejemplos bastante ingeniosos arrojen un poco de luz sobre cuándo realmente quieres que tus punteros compartidos sean pasados por copy. En un programa bien diseñado, siempre debe estar claro quién es responsable de qué recursos, y cuando se usa correctamente, el puntero compartido es una gran herramienta para el trabajo.

 89
Author: Kerrek SB,
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-12-05 13:21:28

Eso depende de lo que quieras. ¿Debería el destinatario compartir la propiedad del objeto? Entonces necesita su propia copia del shared_ptr. Así que pásalo por valor.

Si una función simplemente necesita acceder a un objeto propiedad de la persona que llama, siga adelante y pase por (const) referencia, para evitar la sobrecarga de copiar el shared_ptr.

La mejor práctica en C++ es siempre tener una semántica de propiedad claramente definida para sus objetos. No hay universal "siempre hacer esto" para reemplazar real pensamiento.

Si siempre pasa punteros compartidos por valor, se vuelve costoso (porque son mucho más caros de copiar que un puntero sin procesar). Si nunca lo haces, entonces no tiene sentido usar un puntero compartido en primer lugar.

Copie el puntero compartido cuando una nueva función u objeto necesite compartir la propiedad del puntero.

 23
Author: jalf,
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-12-05 13:02:40

Pásela por referencia constante si pasa por referencia. Eso deja claro que estás pasando por ref por razones de rendimiento. Además, use make_shared cuando pueda, ya que guarda una indirecta, por lo que da un aumento de perf.

 8
Author: Kate Gregory,
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-12-05 12:53:29