c++左值和右值,左值引用和右值引用

简介: c++左值和右值,左值引用和右值引用

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 只是类型转换工具,不会对性能有好处;

目录
相关文章
|
2月前
|
存储 安全 C++
【C++11】右值引用
C++11引入的右值引用(rvalue references)是现代C++的重要特性,允许更高效地处理临时对象,避免不必要的拷贝,提升性能。右值引用与移动语义(move semantics)和完美转发(perfect forwarding)紧密相关,通过移动构造函数和移动赋值运算符,实现了资源的直接转移,提高了大对象和动态资源管理的效率。同时,完美转发技术通过模板参数完美地转发函数参数,保持参数的原始类型,进一步优化了代码性能。
42 2
|
4月前
|
编译器 C++
C++ 11新特性之右值引用
C++ 11新特性之右值引用
59 1
|
6月前
|
存储 安全 C++
浅析C++的指针与引用
虽然指针和引用在C++中都用于间接数据访问,但它们各自拥有独特的特性和应用场景。选择使用指针还是引用,主要取决于程序的具体需求,如是否需要动态内存管理,是否希望变量可以重新指向其他对象等。理解这二者的区别,将有助于开发高效、安全的C++程序。
45 3
|
6月前
|
存储 自然语言处理 编译器
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用
|
6月前
|
C++
C++基础知识(二:引用和new delete)
引用是C++中的一种复合类型,它是某个已存在变量的别名,也就是说引用不是独立的实体,它只是为已存在的变量取了一个新名字。一旦引用被初始化为某个变量,就不能改变引用到另一个变量。引用的主要用途包括函数参数传递、操作符重载等,它可以避免复制大对象的开销,并且使得代码更加直观易读。
|
6月前
|
存储 自然语言处理 编译器
|
6月前
|
安全 C++
|
8天前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
46 18
|
8天前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
34 13