1、什么是左值,右值;
左值可以取地址,位于等号的左边;
右值不能取地址,位于等号的右边;
int a = 10;//a可以通过 & 取地址,位于等号左边,所以a是左值;6位于等号右边,6没法通过
//& 取地址,所以6是个右值;
2、左值引用,右值引用;
引用本质是别名,可通过引用修改变量的值,传参时传引用可以避免拷贝;
1)左值引用;能指向左值,不能指向右值的就是左值引用;
int
a
=
10
;
int
&
refa
=
a
;
//
左值引用指向左值,编译通过
int
&
refa
=
10
;
//
左值引用指向了右值,会编译失败
引用是变量的别名,由于右值没有地址故没法修改,所以左值引用没法指向右值;
但const左值引用可以指向右值:
const
int
&
refa
=
10
;
//
编译通过
const左值引用不会修改指向值
,因此可以指向右值,这也是为什么要使用
const &
作为函数参数的原因之一,如 std::vector
的
push_back
:
void
push_back
(
const
value_type
&
val
);//如果没有 const,vec.push_back(5)
//这样的代码就无法编译通过。
2)右值引用;
右值引用的标志是 && ,右值引用专门为右值而生,可以指向右值,不能指向左值:
int
&&refa_right
=
10
;
// ok
int
a
=
10
;
int
&&
refa_left
=
a
;
//
编译不过,右值引用不可以指向左值
ref_a_right
=
6
;
//
右值引用的用途:可以修改右值
3)右值引用如何指向左值;
int a = 19; // a是个左值
int &refa_left = a; // 左值引用指向左值
int
&&
refa_right
=
std::move
(
a
);
//
通过
std::move
将左值转化为右值,可以被右值引用指向
cout
<<
a
;
//
打印结果:19
std::move
移动不了什么,唯一的功能是把左值强制转化为右值
,让右值引用可以指向左值;其实现等同于一个类型转换: static_cast<T&&>(lvalue)
。 所以,
单纯的
std::move(xxx)不会有性能提升;同样的,右值引用能指向右值
,本质上也是把右值提升为一个左值,并定义一个右值引用通过
std::move指向该左值:
int
&&ref_a
=
5
;
ref_a
=
6
;
等同于以下代码:
int
temp
=
5
;
int
&&
ref_a
=
std::move
(
temp
);
ref_a
=
6
;
4)
左值引用、右值引用本身是左值还是右值?
被声明出来的左、右值引用都是左值;因为被声明出的左右值引用是有地址的,左也位于等号边;仔细看下边代码:
//
形参是个右值引用
void
change
(
int
&&
right_value
) {
right_value
=
8
;
}
int
main
() {
int
a
=
5
;
// a
是个左值
int
&
ref_a_left
=
a
;
// ref_a_left
是个左值引用
int
&&
ref_a_right
=
std::move
(
a
);
// ref_a_right
是个右值引用
change
(
a
);
//
编译不过,
a
是左值,
change
参数要求右值
change
(
ref_a_left
);
//
编译不过,左值引用
ref_a_left
本身也是个左值
change
(
ref_a_right
);
//
编译不过,右值引用
ref_a_right
本身也是个左值
change
(
std::move
(
a
));
//
编译通过
change
(
std::move
(
ref_a_right
));
//
编译通过
change
(
std::move
(
ref_a_left
));
//
编译通过
change
(
5
);
//
当然可以直接接右值,编译通过
cout
<< &
a
<<
' '
;
cout
<< &
ref_a_left
<<
' '
;
cout
<< &
ref_a_right
;
// 打印这三个左值的地址,都是一样的
}
std::move会返回一个右值引用
int &&
,它是左值还是右值呢? 从表达式 int &&ref = std::move(a) 来看,右值引用 ref
指向的必须是右值,所以
move
返回的
int && 是个右值;所以右值引用既可能是左值,又可能是右值吗? 确实如此:右值引用既可以是左值也可以是右值,如果有名称则为左值,否则是右值;或者说:作为函数返回值的 &&
是右值,直接声明出来的
&&
是左值;这同样也符合前面章节对左值,右值的判定方式:其实引用和普通变量是一样的, int &&ref = std::move(a) 和
int a = 5 没有什么区别,等号左边就是左值,右边就是右值;
1、从性能上讲,左右值引用没有区别,传参使用左右值引用都可以避免拷贝;
2、右值引用可以直接指向右值,也可以通过std::move指向左值;而左值引用只能指向左值(const左值引用也能指向右值);
3、作为函数形参时,右值引用更灵活,虽然const左值引用也可以做到左右值都接受,但它无法修改,有一定局限性;
4、std::move 只是类型转换工具,不会对性能有好处;