Yes and no.
Yes, because its legal in this very short example you've shown.
No, because it might result in UB, there are some caveats surrounding usage of an object during destruction
TLDR It's always fine if you don't have any inheritance.
Now, for the cases where it is not fine to use an object during destruction.
The following cases will assume the following is already written
struct V;
struct A;
struct B;
struct D;
void foo(A* a = nullptr);
struct V {
virtual void f();
virtual void g();
};
struct A : virtual V {
virtual void f();
};
struct B : virtual V {
virtual void g();
~B() {
foo();
}
};
struct D : A, B {
virtual void f();
virtual void g();
~D() {
foo(this);
}
};
int main() {
D d;
}
Calling virtual functions
Upon the destruction of x
(aka as soon as its destructor is called)
If the virtual function call uses an explicit class member access and the object expression refers to the complete object of x
or one of that object's base class subobjects but not x
or one of its base class subobjects, the behavior is undefined.
Which means, if you use a explicit class member access to call a virtual function with a pointer pointing to the entirety of x
, but somehow the pointer isn't the type of x
nor its bases, the behaviour is undefined.
void foo(A* a) {
static auto ptr = a;
ptr->g(); // UB when called from ~B
// ptr refers to B, but is neither B nor its base
}
Using typeid
If the operand of typeid
refers to the object under construction or destruction and the static type of the operand is neither the constructor or destructor's class nor one of its bases, the behavior is undefined.
Likewise, if the operand refers to the object being destructed, yet somehow isn't the object and its bases, the behaviour is undefined.
void foo(A* a) {
static auto ptr = a;
typeid(*ptr); // UB when called from ~B()
// ptr refers to B, but is neither B nor its base
}
Using dynamic_cast
If the operand of the dynamic_cast
refers to the object under construction or destruction and the static type of the operand is not a pointer to or object of the constructor or destructor's own class or one of its bases, the dynamic_cast
results in undefined behavior.
Same deal.
void foo(A* a) {
static auto ptr = a;
dynamic_cast<B*>(ptr); // UB when called from ~B()
// ptr refers to B, but is neither B nor its base
}
Conclusion
Now, if you think this is a fiasco and didn't understand what is going on, just don't pass this
anywhere in a destructor.
All quotes from http://eel.is/c++draft/class.cdtor