c++ - ¿Qué tipo de puntero utilizo cuando?




2 Answers

Decidir qué puntero inteligente usar es una cuestión de propiedad . Cuando se trata de la administración de recursos, el objeto A posee el objeto B si controla la vida útil del objeto B. Por ejemplo, las variables miembro son propiedad de sus respectivos objetos porque la vida útil de las variables miembro está vinculada a la vida útil del objeto. Eliges punteros inteligentes en función de cómo se posee el objeto.

Tenga en cuenta que la propiedad en un sistema de software es independiente de la propiedad, ya que podríamos pensar fuera de él. Por ejemplo, una persona puede "poseer" su hogar, pero eso no significa necesariamente que un objeto Person tenga control sobre la vida útil de un objeto House . Combinar estos conceptos del mundo real con conceptos de software es una forma segura de programarse en un agujero.

Si tiene la propiedad exclusiva del objeto, use std::unique_ptr<T> .

Si ha compartido la propiedad del objeto ...
- Si no hay ciclos en la propiedad, use std::shared_ptr<T> .
- Si hay ciclos, define una "dirección" y usa std::shared_ptr<T> en una dirección y std::weak_ptr<T> en la otra.

Si el objeto es suyo, pero existe la posibilidad de que no tenga propietario, utilice los punteros normales T* (por ejemplo, los punteros principales).

Si el objeto es de su propiedad (o si tiene una existencia garantizada), utilice las referencias T& .

Advertencia: tenga en cuenta los costos de los punteros inteligentes. En entornos de memoria o de rendimiento limitado, podría ser beneficioso utilizar punteros normales con un esquema más manual para administrar la memoria.

Los costos:

  • Si tiene un eliminador personalizado (por ejemplo, utiliza grupos de asignación), esto supondrá una sobrecarga por puntero que puede evitarse fácilmente con la eliminación manual.
  • std::shared_ptr tiene la sobrecarga de un incremento en el recuento de referencia en la copia, más un decremento en la destrucción seguido de una verificación de 0 recuentos con la eliminación del objeto retenido. Dependiendo de la implementación, esto puede inflar su código y causar problemas de rendimiento.
  • Tiempo de compilación. Al igual que con todas las plantillas, los punteros inteligentes contribuyen negativamente a los tiempos de compilación.

Ejemplos:

struct BinaryTree
{
    Tree* m_parent;
    std::unique_ptr<BinaryTree> m_children[2]; // or use std::array...
};

Un árbol binario no posee su padre, pero la existencia de un árbol implica la existencia de su padre (o nullptr para la raíz), por lo que utiliza un puntero normal. Un árbol binario (con semántica de valor) tiene propiedad exclusiva de sus hijos, por lo que son std::unique_ptr .

struct ListNode
{
    std::shared_ptr<ListNode> m_next;
    std::weak_ptr<ListNode> m_prev;
};

Aquí, el nodo de lista posee sus listas siguiente y anterior, por lo que definimos una dirección y usamos shared_ptr para next y weak_ptr para prev para romper el ciclo.

c++ pointers c++11 smart-pointers c++-faq

Ok, así que la última vez que escribí C ++ para boost::shared_ptr vida, std::auto_ptr fue todo lo que había disponible en la boost::shared_ptr , y boost::shared_ptr estaba de moda. Realmente nunca busqué en los otros tipos de punteros inteligentes que se proporcionan. Entiendo que C ++ 11 ahora proporciona algunos de los tipos de impulso creados, pero no todos.

Entonces, ¿alguien tiene un algoritmo simple para determinar cuándo usar qué puntero inteligente? Preferiblemente, se incluyen consejos sobre punteros tontos (punteros en bruto como T* ) y el resto de los punteros inteligentes de refuerzo. (Algo así sería genial).




Casos de cuándo usar unique_ptr :

  • Métodos de fábrica
  • Miembros que son punteros (pimpl incluido)
  • Almacenamiento de punteros en contenedores stl (para evitar movimientos)
  • Uso de grandes objetos dinámicos locales.

Casos de cuándo usar shared_ptr :

  • Compartiendo objetos a través de hilos
  • Compartiendo objetos en general

Casos de cuándo usar weak_ptr :

  • Mapa grande que actúa como una referencia general (por ejemplo, un mapa de todos los sockets abiertos)

Siéntase libre de editar y agregar más




Related