Ответ 1
Идея проста, вы определяете базовый класс, который имеет интерфейс с необходимой вам функциональностью, а затем наследует его. Поскольку тип стираемого класса использует только этот интерфейс, фактический тип снизу забывается и стирается. В качестве альтернативы, если только необходимый интерфейс можно выразить как свободные функции, вы можете сохранить указатели на свободные функции.
namespace detail {
struct deleter_base {
virtual ~deleter_base() {}
virtual void operator()( void* ) = 0;
};
template <typename T>
struct deleter : deleter_base {
virtual void operator()( void* p ) {
delete static_cast<T*>(p);
}
};
}
template <typename T>
class simple_ptr {
T* ptr;
detail::deleter_base* deleter;
public:
template <typename U>
simple_ptr( U* p ) {
ptr = p;
deleter = new detail::deleter<U>();
}
~simple_ptr() {
(*deleter)( ptr );
delete deleter;
}
};
Это действительно упрощенный смарт-указатель, но идея есть. В частном случае shared_ptr
делетер хранится как часть объекта счетного отсчета, который удерживается указателем.