In your case option 2 is the best case. You may want to move a pointer to the class, so you do not need to increase and decrease the reference-counter again and again, when you do not need it anymore:
{
shared_ptr<int> ptr = std::make_shared<int>(42);
A a;
a.setI_2(std::move(ptr)); // I no longer need ptr, so I can move it
};
The pointer is moved to the parameter list and ptr
is null/the parameter is initialized with an r-value-reference referring to ptr
, so that ptr gets null. Then it is moved from the parameter list to the member and the parameter is null. You see, there is no (need for a) copy, which implies a change of the reference-counter.
I prefer T const&
only for functions which only read from reference and are not used to initialize another variable. If in the example the third option with the reference is used, the pointer needs to be copied, because the body of setI_3 has a copy in the assignment statement (no move).
The first option is obviously being the worst, because the pointer is copied multiple times.
When you exchange the shared_ptr
with unique_ptr
the compiler forces you to use the fastest way possible -- the moves.
I would add a fourth option:
// Option 4
void setI_4(shared_ptr<int>&& i) { m_i = move(i); }
Note that even of i
beeing an r-value-reference, it is not an r-value-reference when used in the code and so would be copied, when there is no move;
The fourth option only differs from the second option, that the passed parameter always needs to be an r-value-reference, and in the second, i
is a pointer-variable on its own and in the fourth i
is a reference (to something the body of the function can do anything with, but which lives outside the function (the std::move gives permission to do that)). The parameter-variable is constructed from the expression in the parameter-tuple from the caller, the constructor of shared_ptr
automatically copies the pointer (which means that the reference-counter is increased) if it is not an r-value-reference.
The calling of setI_2 works as the following:
{
shared_ptr<int> ptr = std::make_shared<int>(42);
/// ptr owns 42
A a;
{ // a.setI_2(std::move(ptr));
// initializing the parameter
shared_ptr<int> i{std::move(ptr)};
// now i owns 42 and ptr no longer owns it and points to null
{ // the body of the function
a.m_i = std::move(i);
// now a.m_i owns 42 and i no longer owns it and points to null
};
};
};