C ++ 11 lvalue,rvalue和std :: move()

时间:2016-01-14 08:26:45

标签: c++ c++11 overload-resolution rvalue

我有以下代码:

#include <iostream>
using namespace std;
void test(int& a) {
    cout << "lvalue." << endl;
}
void test(int&& a) {
    cout << "rvalue" << endl;
}
int main(int argc, char *argv[]) {
    int a = 1;
    int&& b = 2;
    test(a);
    test(1);
    test(std::move(a));
    test(b);
}

输出:

lvalue.
rvalue
lvalue.
lvalue.

std::move()int&&是右值引用,我想知道为什么test(std::move(a))test(b)输出lvalue?它与签名匹配和函数重载有关吗?

2 个答案:

答案 0 :(得分:8)

输出

lvalue.
rvalue
rvalue
lvalue.

在rvalues和类型为rvalue引用的表达式之间存在非常重要的区别。 b的类型是对int的右值引用,但表达式b是左值;它是一个变量,你可以把它的地址。这就是为什么输出的最后一行是lvalue而不是rvalue。要将其更改为右值,您应该在其上调用std::move

test(std::move(b));

答案 1 :(得分:1)

你可以阅读这篇文章,它很好地解释了Universal References in C++11。还值得一提的是,现在这些引用称为转发引用

在你的情况下,你有

void test(int& a); // lvalue reference overload
void test(int&& a); // rvalue reference overload

第二种情况允许您在函数内实现移动语义或完美转发。虽然第一个也允许它,但只需要使用std::move,它会将其值转换为右值。

test(a);
test(1);
test(std::move(a));
test(b);
  • a有一个名称,因此默认使用移动语义会造成危险的混乱和容易出错,因为我们刚才移动的东西仍然可以在后续的代码行中访问。

  • 1没有名字,你可以拿它的地址,所以它是一个右值。

  • std::move(a)使用std::move将其转为右值,下次使用a时应记住它。

  • ba相同 - 它有一个名称,您可以使用它的地址。

左值和右值的一些例子:

// lvalues:
//
int i = 42;
i = 43; // ok, i is an lvalue
int* p = &i; // ok, i is an lvalue
int& foo();
foo() = 42; // ok, foo() is an lvalue
int* p1 = &foo(); // ok, foo() is an lvalue

// rvalues:
//
int foobar();
int j = 0;
j = foobar(); // ok, foobar() is an rvalue
int* p2 = &foobar(); // error, cannot take the address of an rvalue
j = 42; // ok, 42 is an rvalue