Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding when shared_ptr reference counts are incremented when passing into a function

I have the following Container class

template <typename T>
class Container
{
private:
    std::vector<std::shared_ptr<T>> items_;
public:
    void addItem(std::shared_ptr<T> item)
    {
        std::cout << "useCount addItem pre: " << item.use_count() << std::endl;
        items_.push_back(std::move(item));
        std::cout << "useCount addItem post: " << item.use_count() << std::endl;
    }
};

and I'm calling it like this

int main(int argc, char** argv) {
    std::unique_ptr<Container<std::string>> container = std::make_unique<Container<std::string>>();

    std::shared_ptr<std::string> s = std::make_shared<std::string>("hello");

    std::cout << "useCount main pre: " << s.use_count() << std::endl;

    container->addItem(s);

    std::cout << "useCount main post: " << s.use_count() << std::endl;

    return 0;
}

This is the output I get

useCount main pre: 1
useCount addItem pre: 2
useCount addItem post: 0
useCount main post: 2

Line by line...

  1. Makes sense, there's only one reference to s as soon as its defined

  2. Makes sense, s gets copied into item so its reference count is incremented by 1

  3. I've given items_ ownership of item, so the reference count shouldn't change since addItem has relinquished ownership and transferred it to items_. I expect the reference count to be 2, once from main and once from items_. Instead it's 0.

  4. Makes sense as long as one reference is from main and one reference is from items_.

Thanks for any clarification!

like image 822
Carpetfizz Avatar asked Aug 31 '25 02:08

Carpetfizz


2 Answers

std::move moves the item out of that variable into another one. As one author put it, it "has explicit license to pillage [the variable]." For most std objects, that puts the original object into an unspecified state. However, it appears std:shared_ptr is an exception in that it leaves the object in an empty state.

What all this boils down to is that you can't treat item as the same reference to s anymore after the move. It is in a different state, storing something else. That's why your reference count is off.

If instead you had done this:

std::cout << "useCount addItem post: " << items_.back().use_count() << std::endl;

You would have got the expected output of 2.

After a shared pointer has been moved from, it shall be empty. The use count of an empty shared pointer is 0.

From another point of view, you were expecting that at that point, main, and items_ owned the object (which is correct), but if they are counted in the use_count of the pointer item, then that would be a total of three shared pointers owning the object. That contradicts with your expectation of 2. Of course, this is explained by the fact that item no longer owns the object, so its use count is actually no longer related to other pointers that do own it.

like image 26
eerorika Avatar answered Sep 02 '25 17:09

eerorika



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!