smart punteros pointer inteligentes c++ boost smart-pointers

c++ - pointer - punteros inteligentes(impulso) explicados



smart pointer c++ (4)

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

¡Se agradecerían ejemplos!

  1. scoped_ptr

  2. shared_ptr

  3. weak_ptr

  4. intrusive_ptr

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


Propiedades básicas de los 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
  • cuota de 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 se va a devolver 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 en bruto , sin embargo, los punteros en bruto carecen de una característica importante: no definen si son propietarios o no. Una parte del puntero inteligente de propiedad eliminará el objeto si cada propietario abandona el objeto. Este comportamiento suele ser necesario a menudo, por lo que los punteros inteligentes compartidos de propiedad 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 otra parte. Lo que es más adecuado para los propósitos de RAII donde el puntero inteligente se mantiene local y se crea, por lo que libera un objeto después de que está fuera de alcance.

La participación en 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 no se puede implementar realmente en C ++ actualmente, porque no hay medios para transferir algo de un objeto a otro admitido por el lenguaje: si intenta devolver un objeto desde una función, lo que está sucediendo es que el objeto se copia. Por lo tanto, un puntero inteligente que implementa la transferencia de propiedad debe utilizar el constructor de copia para implementar esa transferencia de propiedad. Sin embargo, esto, a su vez, rompe su uso en contenedores, debido a que los requisitos establecen un cierto comportamiento del constructor de copia de elementos de contenedores que es incompatible con este comportamiento llamado "constructor en movimiento" de estos punteros inteligentes.

C ++ 1x proporciona soporte nativo para la transferencia de propiedad mediante la introducción de los llamados "constructores de movimientos" y "operadores de asignación de movimientos". 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 compartible. Solo se puede utilizar si necesita asignar memoria de manera local, pero asegúrese de que se libere nuevamente cuando esté fuera del alcance. Pero aún se puede cambiar con otro scoped_ptr, si así lo desea.

shared_ptr es un puntero inteligente que comparte la propiedad (tercer tipo anterior). Es una referencia contada para que pueda ver cuándo la última copia queda fuera del alcance 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 shared_ptr) sin agregar un recuento de referencia. Normalmente, necesitaría sacar el puntero en bruto de shared_ptr y copiarlo. Pero eso no sería seguro, ya que no tendría una forma de verificar cuándo se eliminó realmente el objeto. Entonces, weak_ptr proporciona medios al hacer referencia a un objeto administrado por shared_ptr. Si necesita acceder al objeto, puede bloquear su administración (para evitar que en otro hilo, shared_ptr lo libere mientras usa el objeto) y luego usarlo. Si weak_ptr apunta a un objeto que ya se ha eliminado, lo notará lanzando una excepción. El uso de weak_ptr es más beneficioso cuando tiene una referencia cíclica: el conteo de referencias no puede hacer frente con facilidad a tal situación.

intrusive_ptr es como shared_ptr pero no mantiene el recuento de referencia en shared_ptr, pero deja de aumentar / disminuir el recuento a algunas funciones de ayuda 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 externo de conteo de referencias) 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 indicador existente. Mecanismo de conteo de referencias.

unique_ptr es un puntero de transferencia de propiedad. No puede copiarlo, pero puede moverlo utilizando los constructores de movimientos de C ++ 1x:

unique_ptr<type> p(new type); unique_ptr<type> q(p); // not legal! unique_ptr<type> r(move(p)); // legal. p is now empty, but r owns the object unique_ptr<type> 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 el movimiento, no puede proporcionarlos sin escollos. unique_ptr robará automáticamente recursos de otro unique_ptr temporal que es una de las características clave de la semántica de movimientos. auto_ptr quedará en desuso 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. Así que puedes meter unique_ptr''s en un vector, por ejemplo. Pararé aquí y te referiré a un buen artículo sobre esto si quieres leer más sobre esto.


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

  • scoped_ptr : un puntero que se elimina automáticamente cuando queda fuera del alcance. Nota: ninguna asignación es posible, pero no introduce gastos generales
  • intrusive_ptr : puntero de recuento de referencia sin sobrecarga de smart_ptr . Sin embargo, el propio objeto almacena la cuenta de referencias
  • weak_ptr - trabaja junto con shared_ptr para lidiar con las situaciones que resultan en dependencias circulares (lea la documentación y busque en Google una buena imagen;)
  • shared_ptr : el genérico, el más potente (y pesado) de los punteros inteligentes (de los ofrecidos por boost)
  • También existe el antiguo auto_ptr , que garantiza que el objeto al que apunta se destruya automáticamente cuando el control deja un alcance. Sin embargo, tiene diferentes semánticas de copia que el resto de los chicos.
  • unique_ptr - vendrá con C ++ 0x

Respuesta a editar: si


No boost::ptr_container alto boost::ptr_container en cualquier encuesta de impulso de punteros inteligentes. Pueden ser invaluables en situaciones en las que, por ejemplo, un std::vector<boost::shared_ptr<T> > sería demasiado lento.


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

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

shared_ptr es referencia contada. Cada vez que se produce una copia o asignación, se incrementa el recuento de referencia. Cada vez que se dispara el destructor de una instancia, el recuento de referencia para el T * en bruto disminuye. Una vez que es 0, se libera el puntero.

std::vector< shared_ptr<T> > tPtrVec; { shared_ptr<T> 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 compruebes si todavía está cerca de shared_ptr

std::vector< weak_ptr<T> > tPtrVec; { shared_ptr<T> tPtr(new T()); tPtrVec.push_back(tPtr); // num references to T goes from 1->0 } shared_ptr<T> 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 normalmente cuando hay un tercero inteligente que debe usar. Llamará a una función gratuita para agregar y disminuir el recuento de referencia. Consulte el link para aumentar la documentación para obtener más información.