神秘的C++, 这就是C++的一个神秘之处。这是什么?? 我也是很抓狂。
Left Value: 左值:
something you can assign to.
在赋值操作的左边;
可以是address (&foo).
如果它有一个名字,then it is left value.
refer to 一个内存地址,允许我们用&取地址。
Right value:
Something you can't assign to.
如临时变量;temporary object returned by value;
出现在赋值操作的右边。
An rvalue is an expression that is not an lvalue.
int& foo();
int* r = &foo(); // 可以, 因为foo返回的是一个reference, 是一个左值, 可以取地址
int bar();
int* r = &bar(); //不可以,因为bar()返回的是一个rvalue,不能取地址。
rvalue reference:
X& is a lvalue reference.
X&& is a rvalue reference.
Rvalue reference就是对一个无名小卒的reference。
void foo(X& x);
void foo(X&& x);
X x;
X foobar();
foo(x); // 左值引用
foo(foobar()); // 右值引用
这里foo函数被overload. 可以是X& x 的输入,也可以是X&&的输入。
虽然可以任意设计这些overload, 但这样的overload应该之发生在copy和assignment operator上。别的函数不要乱来。
所以这...有什么用呢,说了半天浪费我时间吗?
我们为什么需要知道右值引用呢?
R value reference 可以用来实现move semantics和perfect forwarding
Perfect forwarding改日再说.
Move Semantics主要是用来解决copy constructor和assignment operator(=)虚耗的。
okay. 你说move semantics很Diao我不质疑, 可是为什么要用R value reference?
因为compiler很胆小,只敢欺负Rvalue reference这样的无名小卒, 没有r value reference compiler不敢用move semantics。
比如
MyClass x;
MyClass foo();
x = foo();
如果没有move semantics, 则foo产生的Object会被Copy一下,再assign给x. 如果有了move semantics, 则foo() return的 那个object 可以直接丢给x, 把reference 本身copy一下就好了。 x 原来的那个就直接丢掉了。
这样就要求 MyClass的operator= 需要能接受 rvalue reference(), 因为 x = foo()的右边是个右值。
所以 MyClass 要有一个operator overload
MyClass& operator=(MyClass&& rhs) {
// move semantics
return *this;
}
如果还有一个 operator= overload
MyClass& operator=(MyClass& lhs) {
// 这是一个左值引用
}
那对于两个overloaded的operator=, 一个是左值引用的,一个是右值引用的, compiler怎么选呢?compiler怎么知道用哪一个?
if it has a name, then it is an lvalue. Otherwise, it is an rvalue。 通俗说就是无名小卒。
Move semantics只用来处理那些compiler确定是用完就扔的object, compiler谨小慎微怕出错。
只敢对付无名小卒,但凡有名有姓的,都怕程序员会惦记,不敢碰。
那如果非要用选用右值引用的怎么办?如果我有两个变量 a, b;
MyClass a, b;
如果我想把b转移给a, 让 a = b,
但是 这时compiler会自动选左值引用的 operator=, 没法实现move semantics.
这时 用a = std::move(b) , std::move(b)的返回值就是一个无名小卒。所以强制compiler用右值引用的。这程序员自已把b打成无名小卒,然后丢给compiler说你把它当右值引用。当然程序猿您以后可别惦记b。
网友评论