So I've been messing around trying to implement a variant/tagged union class and needed a way to write generic destructors and made what I thought was a silly mistake forgetting that some types don't have destructors, doing something like
template<typename T>
void destruct(T& thing) {
thing.~T();
}
Yet, this worked fine even with types that didn't have destructors, like int
or struct A {int b;};
. I still think it's more readable and easier to reason with something that uses something like this
template<typename T>
void destruct(T& thing) {
if constexpr(std::is_destructible<T>::value) {
thing.~T();
}
}
But is there actually any difference between the code? The first one feels pretty undefined behavoiry/just wrong to me.
Yet, this worked fine even with types that didn't have destructors, like int or struct A {int b;};
Those are examples of types that are trivially destructible. It is well defined to invoke their "destructor". It has no effects.
But is there actually any difference between the code?
Only for types that are not destructible. Trivially destructible types are destructible.
For non-destructible types such as void
, function types, or types with ~T() = delete;
, the first function is ill-formed while the latter is well-formed with empty body. It depends on the use case which one is more useful, but silently ignoring attempt to destroy something that is not destructible seems dubious to me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With