c++ - 需要 Meyers Effective C++ Widget 右值实例讲解

标签 c++ c++11 rvalue-reference lvalue

我有一个 C++ 的小问题。

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

class Widget {
public:
    Widget(Widget&& rhs);
};

此外,还有评论:“rhs 是左值,尽管它具有右值引用类型”。

老实说,我什么都不懂。 “rhs 是左值,但它的类型是右值引用”是什么意思?

最佳答案

请记住,这里有两件不同的事情:

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

    这决定了函数优先接受什么并且总是“显而易见的”,因为您可以从类型签名(或使用 decltype)中读取它。

  • 另一个是表达式的属性(或值):表达式可以是左值或右值 ( actually, it's more complicated than that... )。

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

    • 左值参数倾向于绑定(bind)到左值引用参数,而
    • 右值参数倾向于绑定(bind)到右值引用参数。

这些属性密切相关(并且在某种意义上彼此“双重”),但它们不一定彼此一致。尤其重要的是要认识到,变量表达式 实际上是不同的东西,因此从形式上讲,它们甚至没有可比性,“苹果对橘子”。


C++ 中有这样一条规则,即使您已将 rhs 声明为右值引用(意味着它将优先匹配作为右值的参数),在在移动构造函数 block 中,变量 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));
}

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

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

关于c++ - 需要 Meyers Effective C++ Widget 右值实例讲解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26962691/

相关文章:

c++ - 一旦成为标准的一部分——boost 库会失去其 boost 命名空间并移至 std 吗?

c++ - 复制线程安全吗?

C++ std::thread 无效使用 void 表达式

c++ - 防止将临时变量作为 const 引用传递的方法,该方法比删除 r 值重载更好地缩放

c++ - 下一个 C++ 标准中即将出现的 R 值引用是什么?

c++ - 需要帮助为文本编辑器程序编写撤消/重做功能

C++ 编程 : Navigating to user files to save my application data for each user

c++ - 定点数的动态格式化

c++ - 右值使用 - C++ 11

c++ - 关于简单 CPU 仿真器实现的问题