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.