Respuestas:
Es fácil cuando tiene propiedades que puede asignar a cada puntero inteligente. Hay tres propiedades importantes.
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 de 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 también se aplica a un puntero sin formato , sin embargo, los punteros sin formato carecen de una característica importante: no definen si son propietarios o no. Un puntero inteligente de propiedad compartida eliminará el objeto si cada propietario abandona el objeto. Este comportamiento es a menudo necesario, por lo que los punteros inteligentes de propiedad compartida están muy extendidos.
Algunos propietarios de punteros inteligentes no admiten ni el segundo ni el tercero. Por lo tanto, no se pueden devolver de las funciones o pasar a otro lugar. Cuál es el más adecuado para RAII
fines en los que el puntero inteligente se mantiene local y se crea para que libere un objeto después de que salga del alcance.
La participación en la propiedad se puede implementar al tener 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 puede implementarse realmente en C ++ actualmente, porque no hay medios para transferir algo de un objeto a otro compatible con 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 tiene que usar el constructor de copias para implementar esa transferencia de propiedad. Sin embargo, esto a su vez interrumpe su uso en contenedores, porque los requisitos establecen un cierto comportamiento del constructor de copia de elementos de contenedores que es incompatible con el comportamiento denominado de "constructor móvil" 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
.
scoped_ptr
es un puntero inteligente que no es transferible ni compartible. Solo se puede usar si necesita asignar memoria localmente, pero asegúrese de que se libere nuevamente cuando salga del alcance. Pero aún puede intercambiarse con otro scoped_ptr, si lo desea.
shared_ptr
es un puntero inteligente que comparte la propiedad (tercer tipo arriba). Se cuenta como referencia para que pueda ver cuándo la última copia queda fuera de alcance y luego libera el objeto administrado.
weak_ptr
es un puntero inteligente no propietario. Se usa para hacer referencia a un objeto administrado (administrado por shared_ptr) sin agregar un recuento de referencia. Normalmente, necesitaría obtener el puntero sin procesar 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 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, 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 fácilmente a tal situación.
intrusive_ptr
es como un shared_ptr, pero no mantiene el recuento de referencia en shared_ptr, sino que deja aumentar / disminuir el recuento a algunas funciones auxiliares que deben definirse por el objeto que se administra. Esto tiene la ventaja de que un objeto ya referenciado (que tiene un recuento de referencia incrementado por un mecanismo de recuento de referencia externo) puede insertarse en un intrusive_ptr, porque el recuento de referencia ya no es interno en el puntero inteligente, pero el puntero inteligente usa un existente Mecanismo de recuento de referencia.
unique_ptr
es un puntero de transferencia de propiedad. No puede copiarlo, pero puede moverlo utilizando los constructores de movimiento 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 moverse, no puede proporcionarlos sin trampas. unique_ptr robará automáticamente recursos de otro temporal unique_ptr, que es una de las características clave de la semántica de movimiento. 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. Por lo tanto, puede insertar unique_ptr en un vector, por ejemplo. Me detendré aquí y lo referiré a un buen artículo sobre esto si desea leer más sobre esto.
auto_ptr
ya está en desuso (C ++ 11).
intrusive_ptr
puede ser preferible para shared_ptr
una mejor coherencia de caché. Aparentemente, el caché funciona mejor si almacena el recuento de referencia como parte de la memoria del objeto administrado en lugar de un objeto separado. Esto se puede implementar en una plantilla o superclase del objeto administrado.
scoped_ptr es el más simple. Cuando se sale del alcance, se destruye. El siguiente código es ilegal (scoped_ptrs no son copiables) 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 una referencia contada. Cada vez que se produce una copia o asignación, el recuento de referencia se incrementa. Cada vez que se dispara el destructor de una instancia, el recuento de referencia para el T * sin procesar se reduce. Una vez que es 0, el puntero se libera.
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 verifiques si el shared_ptr apuntado aún está presente
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 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 aumentar la documentación para obtener más información.
if (tPtrAccessed[0].get() == 0)
supone que es if (tPtrAccessed.get() == 0)
?
No pase boost::ptr_container
por alto en ninguna encuesta de impulso de punteros inteligentes. Pueden ser invaluables en situaciones donde, por ejemplo std::vector<boost::shared_ptr<T> >
, sería demasiado lento.
Secundo el consejo sobre mirar la documentación. No es tan aterrador como parece. Y algunas pistas cortas:
scoped_ptr
- un puntero se elimina automáticamente cuando sale del alcance. Nota: no es posible la asignación, pero no introduce gastos generalesintrusive_ptr
- puntero de recuento de referencia sin sobrecarga de smart_ptr
. Sin embargo, el objeto en sí mismo almacena el recuento de referenciaweak_ptr
- trabaja junto con shared_ptr
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 poderoso (y pesado) de los punteros inteligentes (de los ofrecidos por boost)auto_ptr
, que asegura que el objeto al que apunta se destruye automáticamente cuando el control deja un alcance. Sin embargo, tiene una semántica de copia diferente al resto de los chicos.unique_ptr
- vendrá con C ++ 0xRespuesta a la edición: sí