Reputation: 175
I have class Data which can hold a pointer to an object. I want to be able to call its destructor manually later on, for which I need its address stored in a variable but it seems that taking the address of constructor/destructor is forbidden. Is there any way around this ?
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
}
}
Upvotes: 10
Views: 915
Reputation: 170064
Store a lambda, suitably converted:
void (*_destructor_ptr)(void *v);
// ...
_destructor_ptr = [](void* v) { delete static_cast<T*>(v); };
Note that you must pass _data.data_ptr
for v
. If you intend to store a plain function pointer, the lambda may not capture or implicitly refer to _data.data_ptr
.
Upvotes: 9
Reputation: 10770
I'll also add a solution for smart pointers:
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>());
Upvotes: 2
Reputation: 175
There's also this solution if your compiler doesn't support lambdas:
template<typename T>
struct DestructorHelper {
static void Destroy(void * v) {
delete static_cast<T*>(v);
}
};
and use it as:
_destructor_ptr = &DestructorHelper<T>::Destroy;
Upvotes: 7