indicadores inteligentes (boost) explicados

¿Cuál es la diferencia entre el siguiente conjunto de punteros? ¿Cuándo utiliza cada puntero en el código de producción, si es que lo hace?

¡Ejemplos serían apreciados!

  1. scoped_ptr

  2. shared_ptr

  3. weak_ptr

  4. intrusive_ptr

¿Usas impulso en el código de producción?

Propiedades básicas de punteros inteligentes

Es fácil cuando tiene propiedades que puede asignar a cada puntero inteligente. Hay tres propiedades importantes.

  • ninguna propiedad en absoluto
  • transferencia de la propiedad
  • parte de la propiedad

El primero significa que un puntero inteligente no puede eliminar el objeto, porque no lo posee. El segundo significa que solo un puntero inteligente puede apuntar al mismo objeto al mismo tiempo. Si el puntero inteligente debe devolverse desde las funciones, la propiedad se transfiere al puntero inteligente devuelto, por ejemplo.

El tercero significa que múltiples punteros inteligentes pueden apuntar al mismo objeto al mismo tiempo. Esto se aplica también a un puntero sin formato , sin embargo, los punteros crudos carecen de una característica importante: no definen si son propietarios o no. Una acción del puntero inteligente de propiedad borrará el objeto si cada propietario abandona el objeto. Este comportamiento pasa a ser necesario con frecuencia, por lo que los indicadores inteligentes de posesión compartida están ampliamente difundidos.

Algunos poseedores de punteros inteligentes no admiten ni el segundo ni el tercero. Por lo tanto, no pueden devolverse desde funciones o pasarse a otro lugar. Lo cual es más adecuado para propósitos de RAII donde el puntero inteligente se mantiene local y se acaba de crear para que libere un objeto una vez que se sale del scope.

La parte de la propiedad se puede implementar teniendo un constructor de copia. Esto naturalmente copia un puntero inteligente y tanto la copia como el original harán referencia al mismo objeto. La transferencia de propiedad realmente no se puede implementar en C ++ actualmente, porque no hay medios para transferir algo de un objeto a otro compatible con el idioma: si intentas devolver un objeto desde una función, lo que está sucediendo es que el objeto se copie. Entonces, un puntero inteligente que implementa la transferencia de propiedad tiene que usar el constructor de copia para implementar esa transferencia de propiedad. Sin embargo, esto a su vez interrumpe su uso en contenedores, ya que los requisitos establecen un cierto comportamiento del constructor de copias de los elementos de los contenedores, que es incompatible con el comportamiento denominado “constructor móvil” de estos indicadores inteligentes.

C ++ 1x proporciona soporte nativo para la transferencia de propiedad mediante la introducción de los llamados “constructores de movimiento” y “operadores de asignación de movimiento”. También viene con un puntero inteligente de transferencia de propiedad llamado unique_ptr .

Categorizar punteros inteligentes

scoped_ptr es un puntero inteligente que no es transferible ni se puede compartir. Solo se puede usar si necesita asignar memoria localmente, pero asegúrese de que se libere nuevamente cuando se salga del scope. Pero aún puede intercambiarse con otro scoped_ptr, si así lo desea.

shared_ptr es un puntero inteligente que comparte propiedad (tercer tipo más arriba). Se hace referencia a la referencia para que pueda ver cuándo sale la última copia del scope y luego libera el objeto administrado.

weak_ptr es un puntero inteligente no propietario. Se utiliza para hacer referencia a un objeto administrado (administrado por un shared_ptr) sin agregar un recuento de referencia. Normalmente, necesitarás sacar el puntero sin procesar del shared_ptr y copiar eso. Pero eso no sería seguro, ya que no habría manera de comprobar cuándo se eliminó realmente el objeto. Por lo tanto, weak_ptr proporciona medios al hacer referencia a un objeto administrado por shared_ptr. Si necesita acceder al objeto, puede bloquear la administración del mismo (para evitar que en otro hilo un shared_ptr lo libere mientras usa el objeto) y luego usarlo. Si weak_ptr apunta a un objeto ya eliminado, se dará cuenta lanzando una excepción. El uso de weak_ptr es más beneficioso cuando se tiene una referencia cíclica: el recuento de referencias no puede hacer frente fácilmente a esa situación.

intrusive_ptr es como shared_ptr pero no mantiene el recuento de referencias en shared_ptr pero deja incrementar / disminuir el conteo para algunas funciones auxiliares que deben ser definidas por el objeto que se administra. Esto tiene la ventaja de que un objeto ya referenciado (que tiene un recuento de referencias incrementado por un mecanismo de recuento de referencias externo) se puede rellenar en un intrusive_ptr, porque el recuento de referencias ya no es interno al puntero inteligente, pero el puntero inteligente usa un existente mecanismo de conteo de referencia.

unique_ptr es un puntero de transferencia de propiedad. No puedes copiarlo, pero puedes moverlo usando los constructores de movimiento de C ++ 1x:

 unique_ptr p(new type); unique_ptr q(p); // not legal! unique_ptr r(move(p)); // legal. p is now empty, but r owns the object unique_ptr s(function_returning_a_unique_ptr()); // legal! 

Esta es la semántica que std :: auto_ptr obedece, pero debido a la falta de soporte nativo para moverse, no puede proporcionarlos sin inconvenientes. unique_ptr roba automáticamente los recursos de un otro unique_ptr temporal, que es una de las características clave de la semántica de movimiento. auto_ptr quedará obsoleto en la próxima versión estándar de C ++ a favor de unique_ptr. C ++ 1x también permitirá rellenar objetos que solo se pueden mover pero no se pueden copiar en contenedores. Entonces puedes rellenar unique_ptr’s en un vector, por ejemplo. Me detendré aquí y le haré referencia a un artículo fino sobre esto si quiere leer más sobre esto.

scoped_ptr es el más simple. Cuando sale del scope, se destruye. El siguiente código es ilegal (scoped_ptrs no se puede copiar) pero ilustrará un punto:

 std::vector< scoped_ptr > tPtrVec; { scoped_ptr tPtr(new T()); tPtrVec.push_back(tPtr); // raw T* is freed } tPtrVec[0]->DoSomething(); // accessing freed memory 

shared_ptr es una referencia contada. Cada vez que ocurre una copia o asignación, el recuento de referencias se incrementa. Cada vez que se dispara el destructor de una instancia, se reduce el recuento de referencia para T * sin procesar. Una vez que es 0, el puntero se libera.

 std::vector< shared_ptr > tPtrVec; { shared_ptr tPtr(new T()); // This copy to tPtrVec.push_back and ultimately to the vector storage // causes the reference count to go from 1->2 tPtrVec.push_back(tPtr); // num references to T goes from 2->1 on the destruction of tPtr } tPtrVec[0]->DoSomething(); // raw T* still exists, so this is safe 

weak_ptr es una referencia débil a un puntero compartido que requiere que verifique si el apuntado a shared_ptr todavía está alrededor

 std::vector< weak_ptr > tPtrVec; { shared_ptr tPtr(new T()); tPtrVec.push_back(tPtr); // num references to T goes from 1->0 } shared_ptr tPtrAccessed = tPtrVec[0].lock(); if (tPtrAccessed[0].get() == 0) { cout < < "Raw T* was freed, can't access it" } else { tPtrVec[0]->DoSomething(); // raw } 

intrusive_ptr se usa generalmente cuando hay un ptr inteligente de terceros que debe usar. Llamará a una función gratuita para agregar y disminuir el recuento de referencias. Consulte el enlace para mejorar la documentación para obtener más información.

No boost::ptr_container alto boost::ptr_container en cualquier encuesta de boost smart puninters. Pueden ser invaluables en situaciones donde, por ejemplo, un std::vector > sería demasiado lento.

En segundo lugar, el consejo sobre mirar la documentación. No es tan aterrador como parece. Y algunos consejos cortos:

  • scoped_ptr : un puntero borrado automáticamente cuando sale del scope. Nota: ninguna asignación es posible, pero no introduce gastos generales
  • intrusive_ptr – puntero de conteo de referencia sin sobrecarga de smart_ptr . Sin embargo, el objeto mismo almacena el recuento de referencias
  • weak_ptr : funciona en conjunto con shared_ptr para tratar las situaciones que resultan en dependencias circulares (lea la documentación y busque en Google una buena imagen;)
  • shared_ptr : genérico, más potente (y pesado) de los punteros inteligentes (de los ofrecidos por boost)
  • También existe el antiguo auto_ptr , que asegura que el objeto al que apunta se destruye automáticamente cuando el control deja un ámbito. Sin embargo, tiene una semántica de copia diferente que el rest de los chicos.
  • unique_ptr – vendrá con C ++ 0x

Respuesta a editar: