Given the following code:
#include <iostream>
#include <memory>
struct A {};
struct B : public A {};
std::pair<bool, std::unique_ptr<B>> GetBoolAndB() {
return { true, std::make_unique<B>() };
}
std::unique_ptr<A> GetA1() {
auto[a, b] = GetBoolAndB();
return b;
}
std::unique_ptr<A> GetA2() {
auto [a, b] = GetBoolAndB();
return std::move(b);
}
GetA1
does not compile, with this error:
C2440: 'return': cannot convert from 'std::unique_ptr<B,std::default_delete<_Ty>>' to 'std::unique_ptr<A,std::default_delete<_Ty>>'
while GetA2
does compile without errors.
I don't understand why I need to call std::move
to make the function work.
Edit
Just to clarify, as pointed out in comments by DanielLangr, my doubt was about the fact that
std::unique_ptr<A> GetA3() {
std::unique_ptr<B> b2;
return b2;
}
compiles and transfer ownership without the need for std::move
.
Now I understand that in case of GetA1
and GetA2
, with structured bindings it happens that b
is part of some object, and so it must be moved to become an rvalue reference.
GetA1
you addstd::unique_ptr<B> b2;
andreturn b2;
instead ofreturn b;
, then the code compiles. So the problem seems to be related to the structured binding. On the other hand,static_assert(std::is_same_v<decltype(b), decltype(b2)>);
passes, so I really don't know what's the difference between returningb
or another lobcal object of the same type. – Dissatisfactorystd::unique_ptr
needs to be moved in general, i.e. why it’s non-copyable, or are you asking why it needs to be moved in this specific situation? – Doglikestd::unique_ptr<B> b2; return b2;
, it will compile and transfer ownership without the need forstd::move
. I believe OP is asking why it does not work the same way with structured bindings. – Tertia