【5minC++基本功】——左值与右值|左值引用与右值引用

【5minC++基本功】——左值与右值|左值引用与右值引用
1. 为什么要学习左值与右值?
2.左值和右值的概念
2.1 什么是左值?
2.1.1 常见的左值
2.3 什么是右值?
2.3.1 常见的纯右值
2.2.2 什么是将亡值
2.2.3 产生将亡值的情形
1. 为什么要学习左值与右值?
C++当中的值语义:
GC(Garbage Collection, 垃圾回收)语言之中, 大部分变量都是引用语义, 内存管理交给GC. 通过值语义, 能够方便直观地控制对象的生命周期,让RAII(Resource Acquisition Is Initialization, 即通过构造和析构函数来获取和释放资源,管理变量的生命周期)用起来更自然.

C++ 11中引入了右值引用的概念, 实现移动语义和完美转发, 提高程序的性能和效率. 这也成为C++相关岗位面试中的一大热点, 因此很有必要掌握左值与右值的概念, 以及左值引用和右值引用的相关知识.

2.左值和右值的概念
2.1 什么是左值?
—— 简单地说, 它是指向内存位置的表达式,其值可以被修改, 它的特点是:

可以出在等号左边;
能够取地址
具有别名
2.1.1 常见的左值
变量名
int x = 5;        
1
返回左值引用的函数调
// 返回变量 x 的引用
int& getX() {
    return x;
}

前置自增自减
int y = ++x; // 预增操作,x 先自增再赋值给 y, 这里的++x返回的就是一个左值
++x = 10; // ++x, 自增操作返回一个左值,可以用10对其赋值
1
2
赋值运算或复合赋值运算
++x = 10; // 自增操作返回左值,可以赋值
std::cout << "x: " << x << std::endl; // 输出 10

++x += 3; // 自增操作返回左值,可以进行复合赋值
    std::cout << "x: " << x << std::endl; // 输出 9



解引用
++*ptr = 10; // 自增指针解引用返回左值,可以赋值
1
2.3 什么是右值?
不能被赋值的表达式,通常是临时值或字面常量
右值分为纯右值与将亡值

2.3.1 常见的纯右值
字面值——字面值有整型、浮点数、字符、字符串、布尔型、空指针等, 其中除了字符串型的字面值以外, 其他均为右值.
int a=8; //这里的8就是一个字面值

double b = 3.14;  // 3.14 是右值

char c = 'A';  // 'A' 是右值

bool d = true;  // true 是右值

int* ptr = nullptr;  // nullptr 是右值

const char* str = "Hello";  // "Hello" 是一个指向常量字符数组的左值

非引用类型的函数调用
int add(int a, int b) {
    return a + b;
}

// 不能对右值进行赋值
// add(x, y) = 20; // 错误

后置自增自减
    int a = 5;
    int b = a++; // a++ 返回右值,b 的值是 5,a 的值变为 6
    std::cout << "a: " << a << ", b: " << b << std::endl; // 输出 a: 6, b: 5

    // 不能对右值进行赋值
    // a++ = 10; // 错误

算术表达式
    int a = 10, b = 20;
    int c = a + b; // a + b 返回右值
    std::cout << "c: " << c << std::endl; // 输出 30

    // 不能对右值进行赋值
    // (a + b) = 50; // 错误


逻辑表达式
    bool x = true, y = false;
    bool z = x && y; // x && y 返回右值
    std::cout << "z: " << z << std::endl; // 输出 0 (false)

    // 不能对右值进行赋值
    // (x && y) = true; // 错误


比较表达式
    int a = 5, b = 10;
    bool result = a < b; // a < b 返回右值, 因为a<b是不能被赋值的
    
    // (a < b) = false; //这种写法错误

2.2.2 什么是将亡值
它表示资源即将被移动或者销毁的对象

2.2.3 产生将亡值的情形
std::move 函数的返回值——因为这个函数调用移动赋值运算符而不是拷贝赋值运算符。例如下例:
#include <iostream>
#include <utility> // std::move
#include <string>

class MyClass {
public:
    MyClass() : data(new int[100]) {
        std::cout << "Default constructor" << std::endl;
    }

    ~MyClass() {
        delete[] data;
        std::cout << "Destructor" << std::endl;
    }

    // 移动构造函数
    MyClass(MyClass&& other) noexcept : data(other.data) {
        other.data = nullptr;
        std::cout << "Move constructor" << std::endl;
    }

    // 移动赋值运算符
    MyClass& operator=(MyClass&& other) noexcept {
        if (this != &other) {
            delete[] data;
            data = other.data;
            other.data = nullptr;
            std::cout << "Move assignment operator" << std::endl;
        }
        return *this;
    }

private:
    int* data;
};

int main() {
    //...省略部分obj1的定义
    MyClass obj2;
    obj2 = std::move(obj1); // 这里触发了移动赋值运算符

    return 0;
}

临时对象(尤其是那些通过std::move显式转换的临时对象), 例如:
MyClass createObject() {
    MyClass obj;
    return obj; // 返回值优化 (RVO) 会避免多次拷贝,这里的 obj 是一个将亡值
}

3. 返回右值引用的函数。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/steptoward/article/details/139568337

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值