Как работает boost:: ~ shared_ptr?
при чтении "Вне стандартной библиотеки С++: введение в Boost" у меня появился очень интересный пример:
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;;
}
};
и я немного тестирую:
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
}
что мне очень любопытно, как работает ~ shared_ptr?
как он выводит производный класс B?
Спасибо за помощь!
Спасибо всем,
Я пишу простой пример о том, как работает ~ shared_ptr
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);
}
ключ:
- функция построения шаблона
- ресурс, не удаленный в ~ shared_ptr, удаляется shared_count
Ответы
Ответ 1
Удивительно, что ключ здесь не деструктор boost::shared_ptr
, а его конструктор (ы).
Если вы посмотрите на boost/shared_ptr.hpp
, вы увидите, что shared_ptr<T>
не просто использует конструктор, ожидающий T *
, но:
template<class Y>
explicit shared_ptr( Y * p );
В //3
, когда вы построите boost::shared_ptr
из B *
, преобразование в A *
не выполняется, а внутренние элементы shared_ptr
построены с фактическим типом B
. При уничтожении объекта удаление происходит по указателю B
(не через указатель базового класса).
Ответ 2
Шаблон класса shared_ptr
имеет член типа класса shared_count
, который, в свою очередь, имеет член указателя типа к классу sp_counted_base
. Шаблон конструктора для класса shared_count
присваивает этому экземпляру экземпляр шаблона класса sp_counted_impl_p
, который затенен шаблоном аргументом конструктора, а не shared_ptr::value_type
. sp_counted_base
имеет чистую виртуальную функцию-член dispose
, которая перезаписывается sp_counted_impl_p
. Поскольку sp_counted_impl_p
знает тип B
в вашем примере, он может удалить его без доступа к деструктору базового класса, а поскольку он использует виртуальную отправку, тип определяется во время выполнения. Этот метод требует комбинации параметрического и подтипового полиморфизма.