punteros - smart pointers c++
EliminaciĆ³n de puntero a tipo incompleto y punteros inteligentes (1)
Un shared_ptr
se puede declarar con un tipo incompleto, sí. No es necesario que el tipo esté completo hasta que lo inicialice o restablezca.
Cuando inicializa o restablece un shared_ptr
para que apunte a un nuevo objeto, crea un "eliminador" que se puede usar para destruir el objeto. Por ejemplo, considere lo siguiente:
// somewhere where A is incomplete:
std::shared_ptr<class A> p;
// define A
class A { /* ... */ };
p.reset(new A());
Cuando llama al reset
, A
está completo porque está creando una instancia del mismo utilizando new
. La función de reset
crea y almacena internamente un eliminador que se utilizará para destruir el objeto mediante la delete
. Debido a que A
está completa aquí, esa delete
hará lo correcto.
Al hacer esto, shared_ptr
no requiere que A
esté completo cuando se shared_ptr<A>
; solo requiere que A
esté completo cuando se shared_ptr
constructor shared_ptr
que toma un puntero en bruto o cuando se llama a reset
con un puntero en bruto.
Tenga en cuenta que si A
no está completo cuando realiza una de esas dos cosas, shared_ptr
no hará lo correcto y el comportamiento no está definido (esto se explica en la documentación de boost::shared_ptr
, que es probablemente el mejor recurso para aprender cómo utilizar shared_ptr
correctamente, independientemente de la versión de shared_ptr
que esté utilizando (Boost, TR1, C ++ 0x, etc.)).
Sin embargo, siempre que siga las mejores prácticas de uso para shared_ptr
--notably, si siempre inicializa y restablece un shared_ptr
directamente con un puntero resultante de una llamada a un new
no tendrá que preocuparse por violar esta regla.
Esta funcionalidad no es gratuita: shared_ptr
tiene que crear y almacenar un puntero al functor deleter; Por lo general, esto se hace almacenando el eliminador como parte del bloque que almacena los recuentos de referencias fuertes y débiles o teniendo un puntero como parte de ese bloque que apunta al eliminador (ya que puede proporcionar su propio eliminador).
auto_ptr
(y unique_ptr
también) está diseñado para estar libre de gastos generales: se supone que las operaciones en él son tan eficientes como usar un puntero tonto. Por lo tanto, auto_ptr
no tiene esta funcionalidad.
Al intentar usar un auto_ptr
con un tipo que fue declarado con declaración de reenvío, como esto:
class A;
...
std::auto_ptr<A> a;
no se llama al destructor de A
(aparentemente, porque auto_ptr
delete
internamente s el puntero subyacente y no se puede llamar al destructor para un tipo incompleto).
Sin embargo, el mismo código funciona bien y se llama al destructor cuando se usa std::shared_ptr
lugar de std::auto_ptr
. ¿Cómo se puede explicar eso?