Looking at this implementation of std::shared_ptr
CodePudding user response:
Question 1:
The implementation linked to is not thread-safe at all. You are correct that the shared reference counter should be atomic, not pointers to it. std::atomic<int*>
here makes no sense.
Note that just changing std::atomic<int*>
to std::atomic<int>*
won't be enough to fix this either. For example the destructor is decrementing the reference count and checking it against 0
non-atomically. So another thread could get in between these two operations and then they will both think that they should delete the object causing undefined behavior.
As mentioned by @fabian in the comments, it is also far from a correct non-thread-safe shared pointer implementation. For example with the test case
{
Shared_ptr<int> a(new int);
Shared_ptr<int> b(new int);
b = a;
}
it will leak the second allocation. So it doesn't even do the basics correctly.
Even more, in the simple test case
{
Shared_ptr<int> a(new int);
}
it leaks the allocated memory for the reference counter (which it always leaks).
Question 2:
There is no reason to have a null pointer check there except to avoid printing the message. In fact, if we want to adhere to the standard's specification of std::default_delete
for default_deleter
, then at best it is wrong to check for nullptr
, since that is specified to call delete
unconditionally.
But the only possible edge case where this could matter is if a custom operator delete
would be called that causes some side effect for a null pointer argument. However, it is anyway unspecified whether delete
will call operator delete
if passed a null pointer, so that's not practically relevant either.