C++11 左值、右值和 std::move()
C++11 lvalue, rvalue and std::move()
我有以下代码:
#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
?与签名匹配和函数重载有关吗?
输出应该是:
lvalue.
rvalue
rvalue
lvalue.
右值表达式和右值引用类型的表达式之间有一个非常重要的区别。 b
的类型是对 int
的右值引用,但表达式 b
是左值;它是一个变量,你可以取它的地址。这就是为什么最后一行输出是 lvalue
而不是 rvalue
的原因。为了将其更改为右值,您应该对其调用 std::move
:
test(std::move(b));
你可以看看这篇文章,解释的很好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
有一个名称,因此默认对其应用移动语义会造成危险的混淆,并且 error-prone 因为我们刚刚移动的东西在后续代码行。
1
没有名字,可以取地址,所以是右值
std::move(a)
用std::move
就变成了右值,下次用a
的时候要记得
b
与 a
相同 - 它有一个名称,您可以获取它的地址。
一些左值和右值的例子:
// 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
我有以下代码:
#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
?与签名匹配和函数重载有关吗?
输出应该是:
lvalue.
rvalue
rvalue
lvalue.
右值表达式和右值引用类型的表达式之间有一个非常重要的区别。 b
的类型是对 int
的右值引用,但表达式 b
是左值;它是一个变量,你可以取它的地址。这就是为什么最后一行输出是 lvalue
而不是 rvalue
的原因。为了将其更改为右值,您应该对其调用 std::move
:
test(std::move(b));
你可以看看这篇文章,解释的很好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
有一个名称,因此默认对其应用移动语义会造成危险的混淆,并且 error-prone 因为我们刚刚移动的东西在后续代码行。1
没有名字,可以取地址,所以是右值std::move(a)
用std::move
就变成了右值,下次用a
的时候要记得b
与a
相同 - 它有一个名称,您可以获取它的地址。
一些左值和右值的例子:
// 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