It seems to me that we can call destructor explicitly in this case, could you explain to me why?
Because it's allowed by the language to be able to invoke the destructor of any object whenever you want (assuming you have access, e.g. it's not a private destructor).
What does those destructor call mean in this example?
It just invokes the destructor. Logically, it means that the object is destructed and should be considered to be garbage from that point on and should not be dereferenced or used. Technically it means that the object is in whatever state the destructor leaves it in, which for some objects may be identical to default construction (but you should never, ever rely on that).
Why they are reasonable?
Sometimes you need to destroy objects without releasing their memory. This happens in a lot of class like variant/any, various script binding and reflection system, some singleton implementations, etc.
For example, you might use std::aligned_storage
to allocate a buffer for an object and then use placement new to construct an object in that buffer. You cannot call delete
on this object since that will both invoke the destructor and try to free the memory backing it. You must explicitly invoke the destructor in this case to properly destruct the object.
What are the cases that we can call destructors explicitly besides placement delete?
There's not really such a thing as 'placement delete', other than the corresponding operator to placement new (and any calls to delete
will implicitly invoke the destructor except those the compiler invokes for failed construction, e.g. your 'placement delete' notion).
One example I gave above. Another example is std::vector
. You can call member functions like pop_back()
. This needs to destroy the last element in the vector but it can't use delete
since the memory backing the object is part of a larger buffer that must be managed separately. The same goes for many other containers, like open-addressing hash tables, deque
, and so on. This is an example of where you'd want to use the template typename
in order to invoke the destructor explicitly.
It's a feature that a user of a library is very rarely going to need but the implementor of a low-level library like the STL or even some application frameworks is going to need to use here and there.