2010-12-30 21 views
12

podczas czytania "Beyond the C++ Standard Library: Wprowadzenie do Boost", mam bardzo interesujący przykład:jak działa 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;; 
    } 
}; 

i zrobić kilka testów:

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 

} 

co jestem bardzo ciekawy tutaj jak działa ~ shared_ptr? jak wyprowadzić klasę pochodną B?

Dzięki za pomoc!

dzięki wszystkim napisać prosty próbkę o tym, jak ~ shared_ptr działa

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); 
} 

kluczem jest:

  1. funkcja szablon konstrukt
  2. zasób nie usunięty ~ shared_ptr, to jest usuwany przez udostępniony numer

Odpowiedz

10

Co zaskakujące, klucz tutaj nie jest boost::shared_ptr destruktor, ale jego konstruktor (y).

Jeśli spojrzeć na boost/shared_ptr.hpp, widać że shared_ptr<T> nie „po prostu” mają konstruktor spodziewa się T * ale:

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

W //3 kiedy skonstruować boost::shared_ptr z B *, bez konwersji do A * ma miejsce, a elementy wewnętrzne shared_ptr są zbudowane przy użyciu rzeczywistego typu B. Po zniszczeniu obiektu, usunięcie następuje na wskaźniku B (nie poprzez wskaźnik klasy bazowej).

+1

Pod względem technicznym wykonuje konwersję z B * na A *. Wszystkie późniejsze dojścia do wskaźnika będą korzystać z typu A *. Operacje na typie B odbywają się poprzez standardowy polimorfizm (przechodzą przez A *). Jedynym wyjątkiem jest destruktor, który shared_ptr zapamiętuje za pomocą mechanizmu "deletera" (lub jego generalizacji). – nobar

3

Szablon klasy shared_ptr ma klasę klasy shared_count, która z kolei ma element typu wskaźnik do klasy sp_counted_base. Szablon konstruktora dla klasy shared_count przypisuje wskaźnik do instancji szablonu klasy sp_counted_impl_p temu elementowi, który jest szablonem według typu argumentu konstruktora, a nie przez shared_ptr::value_type. sp_counted_base ma funkcję czystego wirtualnego członka dispose, która jest nadpisywana przez sp_counted_impl_p. Ponieważ sp_counted_impl_p zna typ B w twoim przykładzie, może go usunąć bez dostępu do destruktora klasy podstawowej, a ponieważ używa wirtualnej wysyłki, typ jest określany w środowisku wykonawczym. Ta metoda wymaga połączenia polimorfizmu parametrycznego i podtypu.

Powiązane problemy