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




2 Answers

Propiedad compartida:
El shared_ptr y weak_ptr el estándar adoptado son más o menos los mismos que sus contrapartes Boost . Utilícelos cuando necesite compartir un recurso y no sepa cuál será el último en estar vivo. Utilice weak_ptr para observar el recurso compartido sin influir en su vida útil, no para interrumpir los ciclos. Los ciclos con shared_ptr normalmente no deberían ocurrir: dos recursos no pueden ser propietarios entre sí.

Tenga en cuenta que Boost también ofrece shared_array , que podría ser una alternativa adecuada a shared_ptr<std::vector<T> const> .

A continuación, Boost ofrece intrusive_ptr , que son una solución liviana si su recurso ya cuenta con una administración con conteo de referencias y desea adoptarla según el principio RAII. Este no fue adoptado por la norma.

Propiedad única:
Boost también tiene un scoped_ptr , que no se puede copiar y para el que no puede especificar un borrado. std::unique_ptr es boost::scoped_ptr en los esteroides y debe ser su opción predeterminada cuando necesite un puntero inteligente . Le permite especificar un borrado en sus argumentos de plantilla y es móvil , a diferencia de boost::scoped_ptr . También es totalmente utilizable en contenedores STL siempre que no utilice operaciones que necesiten tipos copiables (obviamente).

Tenga en cuenta de nuevo que Boost tiene una versión de matriz: scoped_array , que se unificó al estándar al requerir la especialización parcial std::unique_ptr<T[]> que delete[] el puntero en lugar de delete (con el default_delete r). std::unique_ptr<T[]> también ofrece el operator[] lugar del operator* y el operator-> .

Tenga en cuenta que std::auto_ptr todavía está en el estándar, pero está en desuso . §D.10 [depr.auto.ptr]

La plantilla de clase auto_ptr está en desuso. [ Nota: la plantilla de clase unique_ptr (20.7.1) proporciona una mejor solución. "Nota final "

Sin propiedad:
Use punteros tontos (punteros en bruto) o referencias para referencias no propietarias a recursos y cuando sepa que el recurso sobrevivirá al objeto / ámbito de referencia. Prefiere referencias y utiliza punteros en bruto cuando necesites nulabilidad o reasentabilidad.

Si desea una referencia no propietaria a un recurso, pero no sabe si el recurso sobrevivirá al objeto que lo hace referencia, empaque el recurso en un shared_ptr y use un weak_ptr . Puede probar si el principal shared_ptr está vivo. lock , que devolverá un shared_ptr que no es nulo si el recurso aún existe. Si desea probar si el recurso está muerto, use expired . Los dos pueden sonar similares, pero son muy diferentes frente a la ejecución concurrente, ya que expired solo garantiza su valor de retorno para esa única declaración. Una prueba aparentemente inocente como

if(!wptr.expired())
  something_assuming_the_resource_is_still_alive();

Es una condición potencial de carrera.

cadenas los

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).




Use unique_ptr<T> todo el tiempo, excepto cuando necesite un conteo de referencias, en cuyo caso use shared_ptr<T> (y, en casos muy raros, weak_ptr<T> para evitar los ciclos de referencia). En casi todos los casos, la propiedad única transferible está bien.

Punteros sin procesar: bueno solo si necesita devoluciones covariantes, apuntando sin propiedad lo que puede suceder. De lo contrario no son terriblemente útiles.

Punteros de la matriz: unique_ptr tiene una especialización para T[] que automáticamente llama a delete[] en el resultado, por lo que puede hacer unique_ptr<int[]> p(new int[42]); por ejemplo. shared_ptr aún necesitaría un eliminador personalizado, pero no necesitaría un puntero de matriz exclusivo o compartido especializado. Por supuesto, tales cosas generalmente son mejor reemplazadas por std::vector todos modos. Desafortunadamente, shared_ptr no proporciona una función de acceso a la matriz, por lo que aún tendría que llamar manualmente a get() , pero unique_ptr<T[]> proporciona operator[] lugar de operator* y operator-> . En cualquier caso, tienes que comprobar límites. Esto hace que shared_ptr sea shared_ptr poco menos fácil de usar, aunque podría decirse que la ventaja genérica y no la dependencia de Boost hace que unique_ptr y shared_ptr los ganadores.

Indicadores de ámbito: hechos irrelevantes por unique_ptr , al igual que auto_ptr .

Realmente no hay nada más que eso. En C ++ 03 sin movimiento semántico esta situación era muy complicada, pero en C ++ 11 el consejo es muy simple.

Todavía hay usos para otros punteros inteligentes, como intrusive_ptr o interprocess_ptr . Sin embargo, son muy nicho y completamente innecesarios en el caso general.




Related