[c++] ¿Qué tipo de puntero uso cuando?



Answers

Decidir qué puntero inteligente usar es una cuestión de propiedad . Cuando se trata de la gestión de recursos, el objeto A posee el objeto B si controla el tiempo de vida del objeto B. Por ejemplo, las variables miembro son propiedad de sus respectivos objetos porque la duración de las variables miembro está vinculada a la duración del objeto. Usted elige 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 pensaríamos en ella fuera del software. Por ejemplo, una persona puede "poseer" su casa, pero eso no significa necesariamente que un objeto Person tenga control sobre la vida útil de un objeto de la House . Confundir estos conceptos del mundo real con conceptos de software es una forma segura de programarte en un agujero.

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

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

Si el objeto lo posee, pero existe la posibilidad de no tener un propietario, utilice los punteros normales T* (por ejemplo, los punteros principales).

Si el objeto lo posee (o si tiene existencia garantizada), use las referencias T& .

Advertencia: tenga en cuenta los costos de los punteros inteligentes. En entornos con memoria o 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 implicará una sobrecarga por puntero que se puede evitar fácilmente mediante la eliminación manual.
  • std::shared_ptr tiene la sobrecarga de un incremento de recuento de referencia en la copia, más una disminución en la destrucción seguida de un conteo de 0 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 indicadores 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 raíz), por lo que utiliza un puntero normal. Un árbol binario (con semántica de valores) tiene la propiedad exclusiva de sus hijos, por lo que estos 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 anterior y siguiente, por lo que definimos una dirección y usamos shared_ptr para next y weak_ptr para prev para romper el ciclo.

Question

Ok, entonces la última vez que escribí C ++ for a living, std::auto_ptr era todo lo que std lib tenía disponible, y boost::shared_ptr estaba de moda. Nunca me fijé realmente en los otros tipos de impulso de puntero inteligente proporcionados. Entiendo que C ++ 11 ahora proporciona algunos de los tipos propuestos, pero no todos.

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




Casos de cuándo usar unique_ptr:

  • Métodos de fábrica
  • Miembros que son punteros (chulos incluidos)
  • Almacenamiento de punteros en stl containters (para evitar movimientos)
  • Uso de grandes objetos dinámicos locales

Casos de cuándo usar shared_ptr:

  • Compartir objetos a través de hilos
  • Enlazar o capturar punteros (uso de lambda o std :: bind)
  • Compartir objetos en general
  • Borradores personalizados

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