Search code examples
c++object-lifetime

Is it really UB to access an object whose user-defined destructor has started, but not finished?


The question arose due to a discussion on Reddit, where a user told me, citing the standard's rules on object lifetime:

I'm pretty certain that it is technically UB to access an object, while it is being destructed.

I rely on this, for example, with classes that manage a background thread; I have their destructors signal the thread to exit and wait until it does, and that thread may access the object. Do I need to refactor my code?


Solution

  • No, it's well-defined.

    If it were UB to access the object at all while its destructor is executing, that destructor would itself not be able to do anything with its own object. 😜


    During execution of your destructor:

    • bases have not been destructed yet
    • the "current" object itself has not been destructed yet (and neither have its members)
    • some resources may have been released, if you did so in your destructor already
    • derived subobjects have been destructed
      • virtual function calls will safely refer to the "current" object, rather than these now-dead derived subobjects
      • dynamic_cast and typeid will do the same
      • you must not do any of these using a Derived*, though! Via a Base* or Current* is fine

    Most of these rules are covered by [class.cdtor].


    Though the object's lifetime does technically end with the beginning of the destructor "call", at this point you're in a kind of purgatory where [class.cdtor] takes over with the rules listed above:

    [basic.life/7]: [..] after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any glvalue that refers to the original object may be used but only in limited ways. For an object under construction or destruction, see [class.cdtor]. [..]

    It's potentially an error-prone and confusing pattern, but it's not inherently incorrect. For your particular use case I'd even call it reasonably conventional.