Compiler doesn't fail when pushing back a std::unique_ptr into a std::vector
std::move(X)
essentially means "here, treat X as if it was a temporary object".
create()
returns a temporary std::unique_ptr<A>
to begin with, so move
is unnecessary.
If you want to know more, look into the value categories. Your compiler uses value categories to determine if an expression refers to a temporary object ("rvalue") or not ("lvalue").
p1
is an lvalue, and create()
is an rvalue.
std::vector::push_back()
has an overload that takes an rvalue reference as input:
void push_back( T&& value );
The return value of create()
is an unnamed temporary, ie an rvalue, so it can be passed as-is to push_back()
without needing to use std::move()
on it.
std::move()
is needed only when passing a named variable, ie an lvalue, where an rvalue is expected.
With C++11 we got move constructors and rvalues semantics.
std::move(X) is just a cast to a rvalue which converts X to X&& that is it. Than move ctor takes the job over and move constructors typically "steal" the resources held by the argument. unique_ptr have a move ctor.
Function return values are already a rvalue(unless the function returns an lvalue reference as indicated by @HolyBlackCat in comments) which will trigger the move ctor without needing any extra cast. And since move ctor is defined for unique_ptr it will compile.
Also the reason why v.push_back(p1);failing is: you try to call copy constructor with an lvalue and it fails because unique_ptr does not have a copy ctor.