// Is proxy_ valid here? or is it undefined behavior?
The pointer is "valid" but refers to the storage of an object whose lifetime has ended.
The lifetime of an object o of type T ends when:
...
- if T is a class type, the destructor call starts, or
See https://eel.is/c++draft/basic.life#1.4
after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that represents the address of the storage location where the object will be or was located may be used but only in limited ways
See https://eel.is/c++draft/basic.life#6
// is proxy_->number_ still valid here?
It maybe shouldn't be, but it is (assuming this was the last outstanding reference to the ProxyImplementation, and so its destructor runs inside the shared_ptr
member destructor. See @ShadowRanger's answer for more details on why that's important). The rules presented below allow access to all member subobjects up until the moment the whole containing object finishes destruction.
The program has undefined behavior if:
...
- the pointer is used to access a non-static data member
See https://eel.is/c++draft/basic.life#6.2
However, there is an escape clause written in, namely
For an object under construction or destruction, see [class.cdtor].
And the rules we find there seem to indicate it will be allowed:
For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes execution results in undefined behavior.
See https://eel.is/c++draft/class.cdtor#1
The destructor body is trivial, but the entire destructor, including compiler-generated calls to member destructors, is non-trivial. It's the latter that matters. But the latter also hasn't finished execution, so by this rule we're still ok.
To form a pointer to (or access the value of) a direct non-static member of an object obj
, the construction of obj
shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior.
See https://eel.is/c++draft/class.cdtor#3
obj
is the Proxy
instance, and its destructor is still in progress, so accessing the member value is still ok according to this rule as well.