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.