Home > database >  Why does the standard disallow a pseudo-destructor call with a name of scalar type?
Why does the standard disallow a pseudo-destructor call with a name of scalar type?

Time:08-28

The standard rules:

[expr.prim.id.unqual]/nt:unqualified-id:

unqualified-id: ...

  • ~ type-name
  • ~ decltype-specifier ...

[dcl.type.simple]/nt:type-name:

type-name:

  • class-name
  • enum-name
  • typedef-name

A name of scalar type isn't a type-name, so the standard disallows the use of it.

It disallows std::destroy_at from being implemented as p->~T() because T may be substituted with a scalar type.

However, the following code compiles:

template <typename T>
void destroy_at(T* p)
{
    p->~T();
}
int main()
{
    int i = 0;
    destroy_at(&i);
}

I don't know why.

What's the point of disallowing such use?

CodePudding user response:

In your implementation of destroy_at the identifier T used in p->~T(); is a type-name per [temp.param]/3. Therefore the call is allowed. Substitution is not relevant.

So the premise that this rule hinders straight-forward implementation of destroy_at is wrong. p->~T(); is just fine.

In fact the only reason pseudo-destructor calls are necessary at all is generic code like this.

If you knew exactly what the type that p points to is while writing the code and you knew it to be non-class, then there wouldn't be any point in writing a pseudo-destructor call. Such a call could practically always be removed without affecting the program (assuming it didn't have undefined behavior to begin with).

The only place where it could affect behavior of the program that I can think of is when testing whether an expression is a constant expression (since C 20). The pseudo-destructor call ends the lifetime of the object and therefore could disqualify an expression that would otherwise be a constant expression from being one.

  • Related