The question about the zero flag and the
xadd instruction has been sufficiently answered by josh. This answer is meant to add some surrounding information about the smart pointer you see.
What you see is typical code for
shared_ptr, the standard reference counting smart pointer in the C++ standard library. A
shared_ptr object (that is the pointer itself, not what it points to!) contains two(!) pointer values. The first pointer points to the pointee, the second pointer points to a management object. The management objects contains the vtable pointer followed by two reference counts, followed by other stuff depending on the specific kind of management object (for example, if the deleter is not stateless, the deleter's state is also included in the management object). The first reference count in the management object contains the number of strong references to the object (i.e. the number of
shared_ptrs pointing to that object), whereas the second reference count contains the number of references to the management object. All strong references together count as a single reference to the management object, but every
weak_ptr counts as an individual further reference to the management object.
Whenever a (non-null)
shared_ptr goes out of scope, the count of strong references is decreased. If the count of strong references reaches zero, the lifetime of pointee ends, and the first vtable function is called to destroy the pointee. This invokes the deleter specified when creating the shared pointer (which (indirectly) defaults to
deletefor arrays) if no deleter was specified). Furthermore, after deletion of the object, the cumulative reference to the management object for all strong references is also decreased. If that reference count reaches zero, the management object can be destroyed, by calling the second vtable function.
When a (non-null)
weak_ptr goes out of scope, just the reference count to the management object is decreased (as the
weak_ptr does not carry a strong reference). If this reference count reaches zero, there are no strong references (because otherwise the cumulative reference to the management would still exist), and no other
weak_ptrs. The pointee has already been destroyed when the last strong reference went out of scope, so just the management object has be destroyed (again, by calling the second vtable entry).
There is an optimization possibility when the pointee and the management object are created at the same time. In that case, the memory for both objects can be allocated in one block. The management object in that case is no bigger than the vtable and the two reference counts and precedes the pointee. The first vfunction just calls the destructor of the pointee, but does not free its memory. The second vfunction destroys the memory block containing the management object and the already destroyed pointee. This optimization is taken when a
shared_ptr is created using
make_shared. The downside of this optimization is that the memory block for the pointee is freed only when no weak or strong refences exist, instead of already then just the strong references are gone. In most use cases of
shared_ptr, there are no
weak_ptrs, so the downside usually does not matter.