Во-первых, в нынешнем виде код не будет работать. Деструктор base
должен быть как минимум protected
(или производные классы должны быть друзьями базы). Деструктор private
означает, что компилятор не позволит вам написать деструктор для производных классов. Теперь, при условии, что у вас есть protected
деструктор ... (Помните, если вы разрабатываете класс для расширения, предоставьте либо открытый виртуальный деструктор , либо защищенный не виртуальный !)
Все зависит от реализации SmartPointer
, в частности std::shared_ptr
(или расширенный аналог boost::shared_ptr
) способны четко управлять этой ситуацией. Решение выполняет своего рода частичное стирание типа для целей уничтожения. По сути, интеллектуальный указатель имеет шаблонный конструктор, который принимает любой указатель, который может быть назначен указателю base
, но поскольку он является шаблонным, он знает конкретный тип. В этот момент он сохраняет синтетическую функцию deleter
, которая будет вызывать соответствующий деструктор.
Для простоты используйте std::function
:
template <typename T>
void delete_deleter( void * p ) {
delete static_cast<T*>(p);
}
template <typename T>
class shared_pointer {
T * ptr;
std::function<void(void*)> deleter;
public:
template <typename U>
shared_pointer( U* p, std::function<void()> d = delete_deleter<U> )
: ptr(p), deleter(d)
{}
~shared_pointer() {
deleter( ptr ); // call the stored destructor
}
};
Код предназначен только для выставок, его нужно настроить для производства (где хранить function
, подсчет ссылок ...), но этого достаточно, чтобы дать вам представление: в единственной функции, где точный тип объекта известен (при создании умного указателя), вы создаете оболочку, которая будет вызывать точную версию деструктора, которая вам нужна (предоставляя некоторую нехватку стирания типа), а затем просто оставляете ее и когда вам нужно delete
объект вызывает его вместо оператора delete
.
Это также может использоваться для управления другими ресурсами, которые требуют вызова специального метода вместо delete
:
// exhibition only!
shared_pointer<Foo> p( Factory.create(), &Factory::release );
Опять же, нужно подготовить довольно много работы, прежде чем готовить этот спектакль.
Зависимость от std::function
, которая используется для упрощения стирания, может быть устранена из проблемы. В простом случае (в интеллектуальном указателе поддерживается только память, выделенная с помощью new
и освобожденная с помощью delete
), затем просто укажите базовый класс deleter
с одним виртуальным operator()(void*)
, а затем выполните рефакторинг существующего delete_deleter
в шаблонные производные классы из deleter
, которые переопределяют operator()(void*)
в текущей реализации. Если вам нужно перейти к общему случаю (держать любой тип ресурса), это не стоит усилий, просто используйте std::function
или boost::function
.