Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why ref_count in shared_ptr implementation is int*

Tags:

c++

shared-ptr

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();
        }
    }
}
like image 654
havij Avatar asked Aug 29 '17 03:08

havij


People also ask

How is shared_ptr implemented C++?

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.

What is the purpose of the shared_ptr <> template?

std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer.

Is shared_ptr reference counting?

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.

What happens when shared_ptr goes out of scope?

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.


1 Answers

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;
        }
    }

Disclaimer

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...).

like image 150
whoan Avatar answered Sep 20 '22 19:09

whoan