首页 文章

为什么C 11具有值参数的隐式移动,而不是rvalue参数?

提问于
浏览
20

在C 11中,值参数(和其他值)在返回时享受隐式移动:

A func(A a) {
    return a; // uses A::A(A&&) if it exists
}

至少在MSVC 2010中,右值参考参数需要 std::move

A func(A && a) {
    return a; // uses A::A(A const&) even if A::A(A&&) exists
}

我认为内部函数,右值引用和值的行为类似,唯一的区别是在值的情况下,函数本身负责销毁,而对于右值引用,责任在外面 .

在标准中对待它们的动机是什么?

2 回答

  • 4

    标准化委员会在创建措辞方面付出了巨大的努力,因此只有在两种情况下才会发生变化:

    • 这样做显然是安全的 .

    • 当用户明确询问时(通过 std::move 或类似的演员) .

    毫无疑问,值参数将在函数末尾被销毁 . 因此,通过移动返回它显然是安全的;返回后它不能被其他代码触及(除非你故意试图破坏事物,在这种情况下你可能会触发未定义的行为) . 因此,它可以从返回中移动 .

    && 变量可能指的是临时变量 . 但它可能指的是左值(一个命名变量) . 因此,离开它是不明显的安全;原始变量可能潜伏着 . 因为你没有明确要求从它移动(即:你没有在这个函数中调用 std::move ),所以不能进行任何移动 .

    只有当你返回时, && 变量才会被隐式移动(即:没有 std::move ) . std::move<T> 返回 T&& . 返回值调用move构造函数是合法的,因为它是返回值 .

    现在很难用左值调用 A func(A &&a) 而不调用 std::move (或等效的强制转换) . 从技术上讲, && 类型的参数可以隐式移动 . 但是,标准委员会希望采取措施明确 && 类型,只是为了确保运动没有使用关于 && 来自何处的功能外知识 .

    通常,在两种情况下,您应该仅通过 && 获取参数:要么're writing a move constructor (or move assignment operator, but even that can be done by value), or you'重新编写转发函数 . 可能还有其他一些情况,但你不应该把 && 带到一个类型,除非你有一些特别的想法 . 如果 A 是可移动类型,则只需按值取值即可 .

  • 24

    在你的第一种情况下,编译器知道 a 正在消失,没有任何东西可以依赖它:显然,这个对象可以被移动,如果不是,它将被销毁 . 在第二种情况下,rvalue引用表明允许从对象移动并且调用者不选择是否利用此权限,并且可能存在函数有时想要从参数移出的原因 . 有时它不想 . 如果编译器可以自由移动此对象,则无法阻止编译器这样做 . 但是,使用 std::move(a) 已经有一种方法可以指示需要从对象移动 .

    标准中的一般规则是编译器只会隐式移动已知会消失的对象 . 当一个rvalue引用进来时,编译器并不真正知道该对象即将离开:如果它明确地是 std::move() ed它实际上保持不变 .

相关问题