return std::move 一个 class 和一个 unique_ptr 成员
return std::move a class with a unique_ptr member
为什么我不能 return 包含 std::unique_ptr
的 class,使用 std::move
语义(我认为),如下例所示?我认为 return 会调用 class A
的移动构造函数,这会 std::move
std::unique_ptr
。 (我使用的是 gcc 11.2,C++20)
示例:
#include <memory>
class A {
public:
explicit A(std::unique_ptr<int> m): m_(std::move(m)) {}
private:
std::unique_ptr<int> m_;
};
A makit(int num) {
auto m = std::make_unique<int>(num);
return std::move(A(m)); // error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]'x86-64 gcc 11.2 #1
}
int main() {
auto a = makit(42);
return 0;
}
我认为解决方案是 return 和 std::unique_ptr
,但在我屈服之前,我想知道为什么移动方法不起作用。
I thought that the return would invoke the move ctor of class A, which would std::move
the std::unique_ptr
.
全部正确,但移动构造函数仅移动 A
的成员。它不能为您移动不相关的卫星唯一指针。
在表达式 A(m)
中,您使用 m
作为左值。这将尝试复制 m
以初始化 A::A
的参数 m
(顺便说一句,糟糕的命名方案来解释所有这些)。如果移动 that,即 A(std::move(m))
,表达式将变得合式。
关于那个主题,std::move(A(...))
中的外部 std::move
是多余的。 A(...)
已经是 A
类型的右值。额外的 std::move
在这里没有任何用处。
简而言之,你不应该 return A
使用 std::move
因为编译器会为你做优化工作(通过一个叫做 RVO 的技巧:What are copy elision and return value optimization?).
另一点是 m_(std::move(m))
中的 std::move
完全没有必要,因为无论使用 std::move
或不是。请记住,std::move
不能保证移动操作并且不会阻止在所有情况下进行处理。
总之,您最好使用 return A( std::move(m) );
而不是 return std::move(A(m));
。在您的 return 声明中, A(m)
已经是 prvalue 并且您不需要将其转换为 xvalue 使用 std::move
以便 return 有效。只需 return 它的 值 编译器就会为你完成这个技巧。
为什么我不能 return 包含 std::unique_ptr
的 class,使用 std::move
语义(我认为),如下例所示?我认为 return 会调用 class A
的移动构造函数,这会 std::move
std::unique_ptr
。 (我使用的是 gcc 11.2,C++20)
示例:
#include <memory>
class A {
public:
explicit A(std::unique_ptr<int> m): m_(std::move(m)) {}
private:
std::unique_ptr<int> m_;
};
A makit(int num) {
auto m = std::make_unique<int>(num);
return std::move(A(m)); // error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]'x86-64 gcc 11.2 #1
}
int main() {
auto a = makit(42);
return 0;
}
我认为解决方案是 return 和 std::unique_ptr
,但在我屈服之前,我想知道为什么移动方法不起作用。
I thought that the return would invoke the move ctor of class A, which would
std::move
thestd::unique_ptr
.
全部正确,但移动构造函数仅移动 A
的成员。它不能为您移动不相关的卫星唯一指针。
在表达式 A(m)
中,您使用 m
作为左值。这将尝试复制 m
以初始化 A::A
的参数 m
(顺便说一句,糟糕的命名方案来解释所有这些)。如果移动 that,即 A(std::move(m))
,表达式将变得合式。
关于那个主题,std::move(A(...))
中的外部 std::move
是多余的。 A(...)
已经是 A
类型的右值。额外的 std::move
在这里没有任何用处。
简而言之,你不应该 return
A
使用std::move
因为编译器会为你做优化工作(通过一个叫做 RVO 的技巧:What are copy elision and return value optimization?).另一点是
m_(std::move(m))
中的std::move
完全没有必要,因为无论使用std::move
或不是。请记住,std::move
不能保证移动操作并且不会阻止在所有情况下进行处理。
总之,您最好使用 return A( std::move(m) );
而不是 return std::move(A(m));
。在您的 return 声明中, A(m)
已经是 prvalue 并且您不需要将其转换为 xvalue 使用 std::move
以便 return 有效。只需 return 它的 值 编译器就会为你完成这个技巧。