I\'m trying to understand exactly how thread-safe, atomic reference counting works, for example as with std::shared_ptr
. I mean, the basic concept is simple, b
The implementation doesn't provide or require such a guarantee, avoidance of the behavior you are describing is predicated on the proper management of counted-references, usually done through a RAII class such as std::shared_ptr
. The key is to entirely avoid passing by raw pointer across scopes. Any function which stores or retains a pointer to the object must take a shared pointer so that it can properly increment the ref count.
void f(shared_ptr p) {
x(p); // pass as a shared ptr
y(p.get()); // pass raw pointer
}
This function was passed a shared_ptr
so the refcount was already 1+. Our local instance, p
, should have bumped the ref_count during copy-assignment. When we called x
if we passed by value we created another ref. If we passed by const ref, we retained our current ref count. If we passed by non-const ref then it's feasible that x()
released the reference and y
is going to be called with null.
If x()
stores/retains the raw pointer, then we may have a problem. When our function returns the refcount might reach 0 and the object might be destroyed. This is our fault for not correctly maintaining ref count.
Consider:
template
void test()
{
shared_ptr p;
{
shared_ptr q(new T); // rc:1
p = q; // rc:2
} // ~q -> rc:1
use(p.get()); // valid
} // ~p -> rc:0 -> delete
vs
template
void test()
{
T* p;
{
shared_ptr q(new T); // rc:1
p = q; // rc:1
} // ~q -> rc:0 -> delete
use(p); // bad: accessing deleted object
}