I have seen several implementations of shared_ptr, for example here. All of them declare ref_count
as int*
. I don't understand what would we lose if it is simply an int
. Thanks!
template <class T>
class shared_ptr {
T* ptr;
int* ref_count;
/**
* Initializes the ref count used for tracking the usage.
*/
void initialize_ref_count() {
if (ref_count != nullptr)
return;
try {
ref_count = new int;
*ref_count = 1;
}
catch (std::bad_alloc& e) {
std::cerr << "Memory allocation error: " << e.what();
}
}
}
A cyclic shared_ptr chain can be broken by changing the code so that one of the references is a weak_ptr . This is done by assigning values between shared pointers and weak pointers, but a weak pointer doesn't affect the reference count. If the only pointers that point to an object are weak, the object is destroyed.
std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer.
The shared reference counter counts the number of owners. Copying a std::shared_ptr increases the reference count by one. Destroying a std::shared_ptr decreases the reference count by one. If the reference count becomes zero, the resource will automatically be released.
The smart pointer has an internal counter which is decreased each time that a std::shared_ptr , pointing to the same resource, goes out of scope – this technique is called reference counting. When the last shared pointer is destroyed, the counter goes to zero, and the memory is deallocated.
As you can see in the implementation you provided (in your link), when a shared pointer is copy constructed or copy assigned, the pointer to the reference counter (ref_count
) is shared between all the instances that manage the same pointer:
// Copy constructor
shared_ptr(const shared_ptr& copy) {
ptr = copy.ptr;
ref_count = copy.ref_count; // see here
if (ref_count != nullptr) {
++(*ref_count);
}
}
// Assignment operator
shared_ptr& operator=(const shared_ptr& copy) {
ptr = copy.ptr;
ref_count = copy.ref_count; // see here
if (ref_count != nullptr) {
++(*ref_count);
}
return *this;
}
In that way, all the instances of that shared pointer, refer to the same memory location to track the ref counter, and the last shared_ptr
will be able to know if it needs to do the cleaning (delete
the allocated memory):
~shared_ptr() {
--(*ref_count);
if (*ref_count == 0) {
delete ref_count;
ref_count = nullptr;
delete ptr;
ptr = nullptr;
}
}
This answer was based in the example provided by the OP for simplicity. A shared_ptr
implementation is far more complicated that the one in the example (think about atomicity, race conditions, etc...).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With