需要Meyers有效的C++ Widget rvalue示例说明

str*_*821 3 c++ lvalue rvalue-reference c++11

我有一个小C++问题.

在Effective Modern C++的第一页上,有一个例子:

class Widget {
public:
    Widget(Widget&& rhs);
};
Run Code Online (Sandbox Code Playgroud)

此外,还有一个评论:'rhs是一个左值,虽然它有一个右值引用类型'.

说实话,我什么都不懂.这是什么意思'rhs是一个左值,但它的类型是右值参考'?

Ruf*_*ind 7

请记住,这里有两个不同的东西:

  • 一个与变量的类型有关:有两种类型的引用:左值引用(&)和右值引用(&&).

    这决定了函数优先接受的内容并且始终是"明显的",因为您可以从类型签名(或使用decltype)中读取它.

  • 另一个是表达式(或值)的属性:表达式可以是左值或右值(实际上,它比那个更复杂......).

    该属性不直接在代码中显示(但有一条经验法则,见下文),但您可以在重载决策中看到它的效果.特别是,

    • lvalue参数更喜欢绑定到lvalue-reference参数,而
    • rvalue参数更喜欢绑定到rvalue-reference参数.

这些属性密切相关(并且在某种意义上彼此"双重"),但它们不一定彼此一致.特别是,重要的是要意识到变量表达式实际上是不同的东西,所以正式地说它们甚至不具有可比性,"苹果到橙子".


在C++中有这样的规则,即使你已经声明rhs为rvalue引用(意味着它将优先匹配rvalues的参数),在移动构造函数的块中,变量rhs本身仍将表现为左值,因此优先匹配接受左值引用的函数.

void test(Widget&&) { std::cout << "test(Widget&&): called\n"; }
void test(Widget&)  { std::cout << "test(Widget&): called\n"; }

Widget::Widget(Widget&& rhs) {
    // here, `rhs` is an lvalue, not an rvalue even though
    // its type is declared to be an rvalue reference

    // for example, this will match `test(Widget&)`
    // rather than the `test(Widget&&)` overload, which may be
    // a bit counter-intuitive
    test(rhs);

    // if you really want to match `test(Widget&&)`
    // you must use `std::move` to "wrap" the variable
    // so that it can be treated as an rvalue
    test(std::move(rhs));
}
Run Code Online (Sandbox Code Playgroud)

这样做的理由是防止移动构造函数中的意外移动.

一般的经验法则是:如果表达式有一个名称(即由一个命名变量组成),那么它就是一个左值.如果表达式是匿名的,那么它就是一个右值.(正如dyp所指出的,这在技术上并不正确 - 请参阅他的评论以获得更正式的描述.)

  • 你使用`std :: move()`去掉它的名字(把它变成一个右值). (2认同)