The following is toy code I am trying... I understand the first and second one. The first one give the ownership to _p
. The second one copies p
to _p
.
but I don't understand the third one...
What does std::move
of const shared_ptr &
mean? Thank you.
class P { };
class A {
public:
// first one
A(std::shared_ptr<P> &p, int) : _p(std::move(p))
{
std::cout << "1st Ctor: "
<< p.use_count() << ", " << _p.use_count() << std::endl;
}
// second one
A(const std::shared_ptr<P> &p, std::string) : _p(p)
{
std::cout << "2nd Ctor: "
<< p.use_count() << ", " << _p.use_count() << std::endl;
}
// third one
A(const std::shared_ptr<P> &p) : _p(std::move(p))
{
std::cout << "3rd Ctor: "
<< p.use_count() << ", " << _p.use_count() << std::endl;
}
private:
std::shared_ptr<P> _p;
};
int main()
{
{
std::shared_ptr<P> p = std::make_shared<P>();
A a(p, 1);
std::cout << "1. body: " << p.use_count() << std::endl;
}
std::cout << "-------------" << std::endl;
{
std::shared_ptr<P> p = std::make_shared<P>();
A a(p, "2");
std::cout << "2. body: " << p.use_count() << std::endl;
}
std::cout << "-------------" << std::endl;
{
std::shared_ptr<P> p = std::make_shared<P>();
A a(p);
std::cout << "3. body: " << p.use_count() << std::endl;
}
}
Result is:
$ ./a.out
1st Ctor: 0, 1
1. body: 0
-------------
2nd Ctor: 2, 2
2. body: 2
-------------
3rd Ctor: 2, 2
3. body: 2
(updated: adding comment to clarify which one is first one, second one, etc.)
std::move
is a function which converts the argument to an rvalue reference. The function call is an xvalue expression.
When the argument is a reference to const, then the result of the conversion is an rvalue to const. If you initialise from rvalue to const, copy constructor will be used because the rvalue reference parameter to non-const of the move constructor cannot bind to rvalue reference argument to const.
I think there is also an implicit question by OP of how
_p(std::move(p))
might differ from_p(p)
_p(std::move(p))
doesn't differ from _p(p)
in case of const std::shared_ptr<T>
.
In theory, if decltype(_p)
was a type that had a constructor T(const T&&)
, then there would be a difference, since that constructor would be invoked by _p(std::move(p))
but not by _p(p)
. Such constructor would be quite unconventional, but technically well-formed. std::shared_ptr
doesn't have such constructor.