2011-04-09 21 views
19

Al intentar utilizar un auto_ptr con un tipo que fue declarado con visión de declaración, así:Supresión del puntero al tipo incompleto y punteros inteligentes

class A; 
... 
std::auto_ptr<A> a; 

el destructor de A no se llama (al parecer, porque auto_ptr internamente delete s no se puede invocar el puntero subyacente y el destructor para un tipo incompleto).

Sin embargo, el mismo código funciona bien y se llama al destructor cuando se utiliza std::shared_ptr en lugar de std::auto_ptr. ¿Cómo se puede explicar eso?

Respuesta

33

A shared_ptr pueden declararse 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 apuntar a un nuevo objeto, crea un "eliminador" que puede usarse 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 se llama a reset, A es completa porque va a crear una instancia del mismo utilizando new. La función reset crea y almacena internamente un eliminador que se usará para destruir el objeto usando delete. Como A se completa aquí, delete hará lo correcto.

Al hacer esto, shared_ptr no requiere que A se complete cuando se declare shared_ptr<A>; solo requiere que se complete A cuando se invoca el constructor shared_ptr que toma un puntero sin formato o cuando se llama al reset con un puntero sin formato.

Tenga en cuenta que si no A es completa cuando haces una de esas dos cosas, shared_ptr no vamos a hacer lo correcto y el comportamiento no está definido (esto se explica en the documentation for boost::shared_ptr, que es probablemente el mejor recurso para el aprendizaje cómo usar shared_ptr correctamente, independientemente de qué versión de shared_ptr esté usando (Boost, TR1, C++ 0x, etc.)).

Sin embargo, siempre y cuando se siga siempre las mejores prácticas de uso de shared_ptr --notably, si siempre inicializar y restablece una shared_ptr directamente con un puntero como resultado de una llamada a new --usted no tendrá que preocuparse violando esta regla.

Esta funcionalidad no es gratuita: shared_ptr tiene que crear y almacenar un puntero al funtor de borrado; por lo general, esto se hace almacenando el eliminador como parte del bloque que almacena los recuentos de referencia 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 no tener gastos generales: se supone que las operaciones en él son igual de eficientes que usar un puntero tonto. Por lo tanto, auto_ptr no tiene esta funcionalidad.

+0

+1! Gracias por la explicación exhaustiva. –

+6

Aquí hay un resumen de los requisitos de integridad para unique_ptr y shared_ptr: http://home.roadrunner.com/~hinnant/incomplete.html –

+2

Durante una hora de material altamente entretenido en shared_ptr, consulte [STL en STL] (http: // channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Advanced-STL-1-of-n). También vale la pena mencionar 'std :: make_shared '. –

Cuestiones relacionadas