【问题标题】:return std::move a class with a unique_ptr member返回 std::move 具有 unique_ptr 成员的类
【发布时间】:2022-01-12 06:08:28
【问题描述】:

为什么我不能使用std::move 语义(我想)返回一个包含std::unique_ptr 的类,如下例所示?我认为返回会调用 A 类的移动 ctor,这将是 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;
}

我相信解决方案是返回 std::unique_ptr,但在我放弃之前,我想知道为什么移动方法不起作用。

【问题讨论】:

  • 这不是移动A,而是移动m,你不要这样做。
  • 您的构造函数按值获取参数,而 unique_ptr 无法做到这一点。
  • @MarkRansom - 是的,你可以。
  • @StoryTeller-UnslanderMonica 真的吗?那么它是如何保持其独特性的呢?
  • @MarkRansom - std::move(m),现在参数从右值初始化并且是唯一的所有者。

标签: c++ unique-ptr stdmove


【解决方案1】:

我认为 return 会调用 A 类的 move ctor,这将 std::move std::unique_ptr

全部正确,但移动构造函数只移动A 的成员。它不能为您移动不相关的卫星唯一指针。

在表达式A(m) 中,您使用m 作为左值。这将尝试复制m 以初始化A::A 的参数m(顺便说一句,糟糕的命名方案来解释所有这些)。如果你移动那个,即A(std::move(m)),表达式就会变得格式良好。

在这个问题上,std::move(A(...)) 中的外部 std::move 是多余的。 A(...) 已经是 A 类型的右值。额外的std::move 在这里没有用处。

【讨论】:

    【解决方案2】:
    • 简而言之,您不应该使用std::move 返回A,因为编译器会为您完成优化工作(通过称为RVO 的技巧:What are copy elision and return value optimization?)。

    • 另一点是m_(std::move(m)) 中的std::move 是完全没有必要的,因为无论是否使用std::moveunique_ptr 的处理都会发生。请记住,std::move 不保证移动操作,也不阻止所有情况下的应对。

    总之,您最好使用return A( std::move(m) ); 而不是return std::move(A(m));。在您的返回语句中,A(m) 已经是 prvalue,您不需要将其转换为 xvalue em> 使用std::move 以便有效地返回它。只需通过 value 返回它,编译器就会为您解决问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-27
      • 2014-11-11
      • 2017-10-19
      相关资源
      最近更新 更多