c++shared-ptrpass-by-valuereference-countingpass-by-const-reference

Passing std::shared_ptr by value or const ref and then storing in a container?


Consider the following vector:

std::vector<std::shared_ptr<X>> myVector;

and the following two functions that add a given element to the vector:

void foo1(std::shared_ptr<X> x)
{
    myVector.push_back(x);
}

void foo2(const std::shared_ptr<X>& x)
{
    myVector.push_back(x);
}

My understanding is that both functions push a shared_ptr to X into the vector and thus increment the ref count of X. The first function results in an additional increment and decrement of the reference count but this is needless.

Is my understanding correct? Is the second option therefore preferable?


Solution

  • In foo1 you pass the parameter (i.e., shared pointer) by value. Thus, the copy constructor of std::shared_ptr<X> is going to be evoked (i.e., ref counter is going to be increased and then decreased when destructor of local copy is being called at } of foo1).

    In foo2 you pass the parameter (i.e., shared pointer) by const reference. Thus, you pass a const qualified alias of the original object (i.e., ref counter is not going to be increased).

    You can also see this in the following example:

    struct X {};
    
    void foo1(std::shared_ptr<X> x) { 
      std::cout << "count in foo1(): " << x.use_count() << std::endl;
    }
    
    void foo2(const std::shared_ptr<X>& x) {
      std::cout << "count in foo2(): " << x.use_count() << std::endl;
    }
    
    int main() {
      std::shared_ptr<X> x(new X);
      std::cout << "count in main(): " << x.use_count() << std::endl;
      foo1(x);
      foo2(x);
    }
    

    Output:

    count in main(): 1
    count in foo1(): 2
    count in foo2(): 1
    

    As you can see in foo1 the number of different shared_ptr instances is 2. That is the original shared_ptr defined in main and the copy in foo1. Whereas, in foo2 the ref counter remains 1.

    Consequently, your reasoning is correct.