patb0
patb0

Reputation: 43

Implicit type of destructor in c++

I know that a destructor in C++ does not return a value and its type cannot be explicitly specified. However, I am wondering whether it can be considered an implicitly void function and whether such a classification is correct according to the C++ standard.

I created a program where type of X destructor is void.

#include <iostream>
#include <cxxabi.h>

using namespace std;

class X
{
};

int main()
{
    X *x = new X();
    char *fullname;

    using destructor_type = decltype(x->~X());
    const type_info  &destructor_t = typeid(destructor_type);

    fullname = abi::__cxa_demangle(destructor_t.name(), NULL, NULL, NULL);
    cout << "[DESTRUCTOR] => " << destructor_t.name() << " => " << fullname << '\n';
    free(fullname);
}

Can you explain to me how it is with destructor?

Upvotes: 4

Views: 122

Answers (1)

aschepler
aschepler

Reputation: 72431

Note that the difference between an ordinary function's type and its return type. Given the declaration

double f(int);

the type of f is double(int) or "function of int returning double". The return type of f is double.

To be technically correct (the best kind of correct):

  • A destructor does not have a type.
  • A destructor does not have a return type.
  • A function call expression whose function part names a destructor (like x->~X()) has type void.

So,

struct X { ~X(); };
X x;

// Both are errors: Naming a destructor can only be done in
// a declaration or definition, or in a call expression with ().
// If they were valid, the destructor has no type anyway.
using T1 = decltype(X::~X);
using T2 = decltype(x.~X);

using T3 = decltype(x.~X());
static_assert(std::is_same_v<T3, void>); // OK

Note that sometimes decltype gives the type from a name's declaration and sometimes it gives a type based on the type and value category of the expression. This is why decltype(a) and decltype((a)) can be different things. But x.~X() is not directly naming the destructor, so it falls into the category of just getting the expression type, not involving the declaration (explicit or implicit) of ~X.

It's true a destructor is in many ways like a function with return type void: You can use the statement return;, you can't use return with any actual value, and you can't get a value from an expression that calls it.

But there's one little difference showing that a destructor doesn't actually have return type void: A function with return type void can return an expression that has type void. A destructor can't return any expression, even if it does have type void.

void f();

void g(bool b) {
    if (b)
        return f();    // OK, returning void expression as void
    else
        return void(); // Strange but valid way of writing "return;"
}

Y::~Y() {
    if (this->b)
        return f();    // Error, can't put anything after "return"
    else
        return void(); // Error
}

Upvotes: 5

Related Questions