2010-12-30 9 views
12

al leer "Más allá de la biblioteca C++ estándar: Una introducción a la Boost", tengo un ejemplo muy interesante:cómo funciona boost :: ~ shared_ptr?

class A 
{ 
public: 
    virtual void sing()=0; 
protected: 
    virtual ~A() {}; 
}; 

class B : public A 
{ 
public: 
    virtual void sing() 
    { 
     std::cout << "Do re mi fa so la"<<std::endl;; 
    } 
}; 

y hacer algunas pruebas:

int main() 
{ 

//1 
std::auto_ptr<A> a(new B); //will not compile ,error: ‘virtual A::~A()’ is protected 

//2 
A *pa = new B; 
delete pa; //will not compile ,error: ‘virtual A::~A()’ is protected 
delete (dynamic_cast<B*>(pa)); //ok 

//3 
boost::shared_ptr<A> a(new B);//ok 

} 

lo que soy muy curioso aquí ¿Cómo funciona ~ shared_ptr? cómo se deduce la clase derivada B?

Gracias por su ayuda!

gracias a todos, escribo una simple muestra de cómo ~ shared_ptr funciona

class sp_counted_base 
{ 
public: 
    virtual ~sp_counted_base(){} 
}; 

template<typename T> 
class sp_counted_base_impl : public sp_counted_base 
{ 
public: 
    sp_counted_base_impl(T *t):t_(t){} 
    ~sp_counted_base_impl(){delete t_;} 
private: 
    T *t_; 
}; 


class shared_count 
{ 
public: 
    static int count_; 
    template<typename T> 
    shared_count(T *t): 
     t_(new sp_counted_base_impl<T>(t)) 
    { 
     count_ ++; 
    } 
    void release() 
    { 
     --count_; 
     if(0 == count_) delete t_; 
    } 
    ~shared_count() 
    { 
     release(); 
    } 
private: 
    sp_counted_base *t_; 
}; 
int shared_count::count_(0); 

template<typename T> 
class myautoptr 
{ 
public: 
    template<typename Y> 
    myautoptr(Y* y):sc_(y),t_(y){} 
    ~myautoptr(){ sc_.release();} 
private: 
    shared_count sc_; 
    T *t_; 
}; 

int main() 
{ 
    myautoptr<A> a(new B); 
} 

la clave es:

  1. función de plantilla constructo
  2. el recurso no elimina en ~ shared_ptr, se es eliminado por shared_count

Respuesta

10

Sorprendentemente, el La clave aquí no es boost::shared_ptr destructor sino su constructor (es).

Si nos fijamos en boost/shared_ptr.hpp, se verá que shared_ptr<T> no 'simplemente' tiene un constructor esperando un T * pero:

template<class Y> 
explicit shared_ptr(Y * p); 

En //3 cuando se construye un boost::shared_ptr de un B *, sin conversión a A * se lleva a cabo, y las partes internas shared_ptr se construyen con el tipo real B. Tras la destrucción del objeto, la eliminación se produce en un puntero B (no a través de un puntero de clase base).

+1

Técnicamente hablando, REALIZA una conversión de B * a A *. Todos los accesos posteriores al puntero usarán el tipo A *. Las operaciones en tipo B son a través de polimorfismo estándar (pasan por A *). La única excepción es el destructor, que shared_ptr recuerda a través de su mecanismo "deleter" (o alguna generalización del mismo). – nobar

3

La plantilla de clase shared_ptr tiene un miembro del tipo de clase shared_count, que a su vez tiene un miembro de tipo puntero a la clase sp_counted_base. La plantilla de constructor para la clase shared_count asigna un puntero a una instancia de la plantilla de clase sp_counted_impl_p a este miembro que está modelado por el tipo del argumento de constructor, no por el shared_ptr::value_type. sp_counted_base tiene una función de miembro virtual pura dispose que se sobrescribe por sp_counted_impl_p. Como sp_counted_impl_p conoce el tipo B en su ejemplo, puede eliminarlo sin acceso al destructor de la clase base, y debido a que utiliza el despacho virtual, el tipo se determina en tiempo de ejecución. Este método requiere una combinación de polimorfismo paramétrico y de subtipo.

Cuestiones relacionadas