Могу ли я вызвать виртуальный деструктор, используя указатель на функцию?

У меня есть класс данных, который может содержать указатель на объект. Я хочу иметь возможность позже вызывать деструктор вручную, для чего мне нужно, чтобы его адрес хранился в переменной, но кажется, что взятие адреса конструктора / деструктора запрещено. Есть ли способ обойти это?

struct Data {

union {
long i;
float f;
void* data_ptr;
} _data;

std::type_index _typeIndex;
void (*_destructor_ptr)();

template<typename T>
void Init() {
if constexpr (std::is_integral<T>::value) {
//
}
else if constexpr (std::is_floating_point<T>::value) {
//
}
else {
_data.data_ptr = new T;
_typeIndex = std::type_index(typeid(T));
_destructor_ptr = &T::~T; // << -- can't do this
}
}

10

Решение

Храните лямбду, соответствующим образом преобразованную:

void (*_destructor_ptr)(void *v);

// ...

_destructor_ptr = [](void* v) { delete static_cast<T*>(v); };

Обратите внимание, что вы должны пройти _data.data_ptr за v, Если вы намереваетесь хранить простой указатель на функцию, лямбда может не захватить или неявно обратиться к _data.data_ptr,

9

Другие решения

Также есть решение, если ваш компилятор не поддерживает лямбда-выражения:

template<typename T>
struct DestructorHelper {
static void Destroy(void * v) {
delete static_cast<T*>(v);
}
};

и использовать его как:

_destructor_ptr = &DestructorHelper<T>::Destroy;
7

Я также добавлю решение для умных указателей:

template <class T>
struct DataPtrDeleter
{
void operator()(void * p) { delete (T*)p; }
}

std::shared_ptr<void*> data_ptr(new T, DataPtrDeleter<T>());
//or
std::unique_ptr<void*, DataPtrDeleter<T>> data_ptr(new T, DataPtrDeleter<T>());
1
По вопросам рекламы [email protected]