Debo usar el rpp compartido o el único


He estado haciendo algunos objetos usando el modismo pimpl, pero no estoy seguro de si usarstd::shared_ptr o std::unique_ptr.

Entiendo que std::unique_ptr es más eficiente, pero esto no es un problema para mí, ya que estos objetos son relativamente pesados de todos modos, por lo que el costo de std::shared_ptr sobre std::unique_ptr es relativamente menor.

Actualmente voy con std::shared_ptr solo por la flexibilidad adicional. Por ejemplo, usar un std::shared_ptr me permite almacenar estos objetos en un hashmap para acceso rápido sin dejar de ser capaz de devolver copias de estos objetos a las personas que llaman (ya que creo que cualquier iterador o referencia puede convertirse rápidamente en inválido).

Sin embargo, estos objetos de alguna manera realmente no se están copiando, ya que los cambios afectan a todas las copias, así que me preguntaba que tal vez usar std::shared_ptr y permitir copias es algún tipo de anti-patrón o algo malo.

Es esto correcto?

Author: Nic Hartley, 2011-04-07

4 answers

He estado haciendo algunos objetos usando el modismo pimpl, pero no estoy seguro de si usar shared_ptr o unique_ptr.

Definitivamente unique_ptr o scoped_ptr.

Pimpl no es un patrón, sino un modismo, que se ocupa de la dependencia en tiempo de compilación y la compatibilidad binaria. No debe afectar la semántica de los objetos, especialmente con respecto a su comportamiento de copia.

Puede usar cualquier tipo de puntero inteligente que desee debajo del capó, pero esos 2 garantizan que no compartirá accidentalmente la implementación entre dos objetos distintos, ya que requieren una decisión consciente sobre la implementación del constructor de copia y el operador de asignación.

Sin embargo, estos objetos de alguna manera realmente no se están copiando, ya que los cambios afectan a todas las copias, así que me preguntaba que tal vez usar shared_ptr y permitir copias es algún tipo de anti-patrón o algo malo.

No es un anti-patrón, de hecho, es un patrón: Aliasing. Ya utilizar, en C++, con los punteros y referencias. shared_ptr ofrecen una medida adicional de "seguridad" para evitar referencias muertas, a costa de complejidad adicional y nuevos problemas (cuidado con los ciclos que crean fugas de memoria).


No relacionado con Pimpl

Entiendo que unique_ptr es más eficiente, pero esto no es un problema para mí, ya que estos objetos son relativamente pesados de todos modos, por lo que el costo de shared_ptr sobre unique_ptr es relativamente menor.

Si puede factorizar algún estado, es posible que desee echar un vistazo a la Peso mosca patrón.

 34
Author: Matthieu M.,
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-07 07:11:25

Si usas shared_ptr, no es realmente el pimpl clásico idioma (a menos que tome medidas adicionales). Pero la verdadera pregunta es por eso que desea utilizar un puntero inteligente para empezar; es muy claro donde el delete debe ocurrir, y no hay problema de seguridad de excepción u otro de que preocuparse. Como mucho, un puntero inteligente le ahorrará una línea o dos de código. Y el solo uno que tiene la semántica correcta es boost::scoped_ptr, y no creo que funcione en este caso. (IIRC, requiere un tipo completo para ser instanciado, pero podría ser Equivocada.)

Un aspecto importante del modismo pimpl es que su uso debe ser transparente para el cliente; la clase debe comportarse exactamente como si se implementó clásicamente. Esto significa o bien inhibir copia y asignación o implementación de copia profunda, a menos que la clase es inmutable (no hay funciones miembro no-const). Nada de lo habitual punteros inteligentes implementar copia profunda; se podría implementar uno, de por supuesto, pero probablemente todavía requeriría un tipo completo cada vez que se produce la copia, lo que significa que todavía tendría que proporcionar un constructor de copia definido por el usuario y un operador de asignación (ya que no pueden estar en línea). Dado esto, probablemente no vale la pena usar el puntero inteligente.

Una excepción es si los objetos son inmutables. En este caso, se no importa si la copia es profunda o no, y shared_ptr maneja la situación completamente.

 9
Author: James Kanze,
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-07 08:23:28

Cuando usa un shared_ptr (por ejemplo, en un contenedor, luego busque esto y devuelva by-value), no está causando una copia del objeto al que apunta, simplemente una copia del puntero con un recuento de referencia.

Esto significa que si modifica el objeto subyacente desde varios puntos, entonces afecta los cambios en la misma instancia . Esto es exactamente para lo que está diseñado, por lo que no algunos anti-patrón!

Al pasar un shared_ptr (como dicen los comentarios,) es es mejor pasar por referencia const y copiar (allí aumentando el recuento de referencias) cuando sea necesario. En cuanto a la devolución, caso por caso.

 5
Author: Nim,
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
2017-06-13 07:01:36

Sí, por favor úselos. En pocas palabras, shared_ptr es una implementación de smart pointer. unique_ptr es una implementación de puntero automático:

 1
Author: Trombe,
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
2017-08-07 07:53:52