Destructor call for scalar types & undefined behavior [duplicate]
Asked Answered
A

1

2

I just wrote following program & it compiles & runs fine. (see live demo here.)

#include <iostream>
typedef int T;
int main()
{
    int a=3;
    std::cout<<a<<'\n';
    a.~T();
    std::cout<<a;
    return 0;
}

Why the program compiles fine? If I am not wrong scalar types don't have constructor and destructor in C++. So, is this program well defined? Does explicit call to destructor destroys variable a in this case or it will be automatically destroyed by compiler when execution of function completes? I know that accessing an object after its lifetime has ended has undefined behaviour in C++. But what the C++ standard says about this?

I found little similar question here on SO. The answer given by @Columbo says that:

You can't call a destructor for scalar types, because they don't have one. The statement is solely allowed for template code in which you call the destructor of an object whose type you don't know - it removes the necessity of writing a specialization for scalar (or even array) types.

So, I don't understand the explanation given by him. It would be better if someone explains it using template code in which destructor is called of an object whose type isn't known. I would be thankful if someone explains this using simple example.

Axum answered 26/8, 2015 at 3:25 Comment(5)
@vsoftco: why no one has given an answer so far? SO is quick when every time I post any question, but this time looks so slow.Axum
I have linked to the exact same question asked elsewhere - although that question doesn't have a complete answer yet, it will be bumped by the linkingCauserie
@vsoftco ok, erasingCauserie
Can someone comment if the program is legal? Can we explicitly call the (trivial) destructor on a fundamental type (even though we call it via a typedef)? Both g++ and clang++ don't complain though...Metaphor
@Metaphor It's legal, and Columbo's linked answer states why ... when you make a pseudo destructor call, like that in the example above, the only thing that happens is the expression to the left of the dot is evaluated. IOW, the destructor call itself is a NOP.Fayre
H
0

According to this:

A trivial destructor is a destructor that performs no action. Objects with trivial destructors don't require a delete-expression and may be disposed of by simply deallocating their storage. All data types compatible with the C language (POD types) are trivially destructible.

Probably it is similary to the fact that in C++ you can initialize any POD type object like any class type object, by calling its constructor with (init_val) for example int i(-1);

But notice that by definition calling a destructor directly for an ordinary object, such as a local variable, invokes undefined behavior when the destructor is called again, at the end of scope.

Hobgoblin answered 26/8, 2015 at 4:2 Comment(15)
The "no action" there really means what it says. A trivial destructor can be invoked multiple times or not at all, and it makes no difference. (No UB.)Nellynelms
@Nellynelms the definition of trivial destructor in 12.4 suggests that only class types may have a destructor (let alone a trivial destructor, which is the non-user-declared destructor of a class meeting certain requirements)Causerie
@AlexLop. your answer seems to contradict itself, are you saying that OP's code causes undefined behaviour or not?Causerie
@MattMcNabb Fair nuff, but a pseudo-destructor-call has the same semantics as a trivial destructor.Nellynelms
@Nellynelms So you are saying that OP's code here causes UB by accessing a after its lifetime ends (because trivial destructors end the lifetime of their object, and you say the pseudo-destructor-call has the same semantics). However Columbo's answer on the duplicate thread seems to be saying that it does not cause UB because the pseudo-destructor has no effect, although he isn't completely clear about that.Causerie
@Potatoswatter, Matt McNabb: still doesn't answer my question. It would be better if you write an answer that explains it using template code in which destructor is called of an object whose type isn't known.Axum
@MattMcNabb [basic.life]/1 states that the lifetime of an object of class type with a non-trivial destructor is ended when the destructor call starts, so the example in the OP doesn't end the lifetime of the int. And that goes back to what Columbo states, scalar types don't have destructors, and the psuedo destructor call doesn't do anything.Fayre
@PravasiMeet see Columbo's answer. His answer could be clarified a little but I don't have anything to add to it.Causerie
@MattMcNabb I am saying that calling the distructor of an ordinary object explicitly has undefined behavior. In case of POD types it probably does nothing but I couldn't find anything official that has such statement.Hobgoblin
@AlexLop. objects of POD type or int are objects, I'm not sure what distinction you are drawing with the word "ordinary"Causerie
@MattMcNabb No. I said a trivial destructor has no effect. It does not end the lifetime of anything. Nor does a pseudo-destructor-call. There's no UB.Nellynelms
@Nellynelms I'd consider "ending lifetime" and "not ending lifetime" to be different semantics !Causerie
@MattMcNabb I never said anything about a lifetime ending. All my comments have unambiguously said that these constructs do absolutely nothing. What are you talking about?Nellynelms
… Perhaps you should ask a question with your concern. I think you are under the impression that the destructor of a trivially destructible class has some subtle meaning. It doesn't.Nellynelms
@Nellynelms OK, I see now that objects of class type which have a trivial destructor do not have their lifetime ended by calling their destructor. So struct A { int x; } a; a.~A(); a.~A(); is legal.Causerie

© 2022 - 2024 — McMap. All rights reserved.