Destructors of builtin types (int, char etc..)

Nils Pipenbrinck picture Nils Pipenbrinck · Jan 19, 2009 · Viewed 9.2k times · Source

In C++ the following code gives a compiler error:

void destruct1 (int * item)
{
  item->~int();
}

This code is nearly the same, I just typedef the int to another type and something magic happens:

typedef int myint;

void destruct2 (myint * item)
{
  item->~myint();
}

Why does the second code work? Does an int get a destructor just because it has been typedefed?

In case you wonder why one ever would like to do this: This comes from refactoring C++ code. We're removing the standard heap and replacing it with selfmade pools. This requires us to call placement-new and the destructors. I know that calling destructors for primitive types is useless, but we want them in the code nevertheless in case we later replace PODs with real classes.

Finding out that naked int's don't work but typedefed ones do was quite a surprise.

Btw - I have a solution that involves template-functions. We just typedef inside the template and everything is fine.

Answer

Johannes Schaub - litb picture Johannes Schaub - litb · Jan 19, 2009

It's the reason that makes your code work for generic parameters. Consider a container C:

template<typename T>
struct C {
    // ...
    ~C() {
        for(size_t i = 0; i<elements; i++)
            buffer[i].~T();
    }
};

It would be annoying to introduce special cases for built-in types. So C++ allows you to do the above, even if T happens to equal to int. The holy Standard says in 12.4 p15:

The notation for explicit call of a destructor can be used for any scalar type name. Allowing this makes it possible to write code without having to know if a destructor exists for a given type.

The difference between using a plain int and a typedef'ed int is that they are syntactically different things. The rule is, that in a destructor call, the thing after the ~ is a type-name. int is not such a thing, but a typedef-name is. Look it up in 7.1.5.2.