Passing the "this" pointer to another class / function in the destructor

Is it legal C ++ to create a work object on the stack in the destructor of some main object and pass the this pointer of the main object to the auxiliary object? Then the helper object also calls member functions of the main object or access member variables.

In other words, is the following legal C ++?

 struct MasterClass { MasterClass (int data); ~MasterClass (); int data; }; struct WorkerClass { WorkerClass (MasterClass *m) : m (m) { } void do_some_work () { m->data = 42; } MasterClass *m; }; MasterClass::MasterClass (int data) : data (data) { } MasterClass::~MasterClass () { WorkerClass w (this); w.do_some_work (); } int main () { MasterClass m (7); } 

I understand that the lifetime of the main object ends when the destructor begins to execute. But I consider it legal to call non-virtual member functions in the destructor of any object that use the implicit argument / parameter this .

+8
c ++ this c ++ 11 destructor object-lifetime
source share
2 answers

Yes and no.

Yes, because it is legal in this very short example that you showed.

No, because it can lead to UB, there are some caveats related to using the object during destruction

TL; DR This is always normal if you do not have inheritance.

Now for cases when it is impractical to use the object during destruction.

In the following cases, it is assumed that it 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; } 

Virtual function call

After the destruction of x (also as soon as its destructor is called)

If a call to a virtual function uses explicit access to a class member, and the expression of the object refers to the full object x or to one of the subobjects of the base class of the object, but not to x or one of its Saturdays of the base class, the behavior is undefined.

This means that if you use an explicit class member to call a virtual function with a pointer pointing to the entire text of x , but somehow the pointer is not a type of x and its base, the behavior 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 typeid operand refers to the object being built or destroyed, and the static type of the operand is neither a constructor class, nor a destructor, nor its base, the behavior is undefined.

Similarly, if the operand refers to a destructible object, but somehow it is not an object and its basics, the behavior 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 dynamic_cast operand refers to an object under construction or destruction, and the static operand type is not a pointer to an object or object of its own constructor or destructor class or one of its bases, dynamic_cast leads to undefined behavior.

The same thing.

 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 don’t understand what is happening, just don’t miss this anywhere in the destructor.

All quotes from http://eel.is/c++draft/class.cdtor

+7
source share

Yes, this is legal because the main object will not be destroyed until the destructor completes.

However, this is not good practice in general.

+1
source share

All Articles