it编程 > 编程语言 > C/C++

c/c++中的左值右值详解

40人参与 2025-04-08 C/C++

左值 (lvalue)

定义:

右值 (rvalue)

定义:

左值和右值主要的区别之一是左值可以被修改,而右值不能。

int number;
number = 1

在这段代码中 number 为左值 ,1 为右值。

// getvalue()返回的临时值是右值
int value = getvalue();

引用的本质是别名,可以通过引用改变变量的值,传参时传引用可以避免拷贝。

左值引用 (lvalue reference)

定义: 引用一个对象;

基本用法:

    int number = 10;
    int& count = number;
    count++; // number = count = 11;
void addcount(int& count)
{
    count++;
}

int number = 10;
addcount(number);

如果给“左值”引用直接赋“右值”,则会报错,例:

int& number = 10;
报错:
错误 c2440	“初始化”: 无法从“int”转换为“int &”	

const 左值引用不会修改指向值,因此可以指向右值

例如:

std::vector 中的方法 push_back

// 如果没有 const 那么使用 v.push_back(10) 这样 10 的类型是右值,就无法通过编译了
void push_back(const value_type& _val)

// 可以直接传递字面值
v.push_back(10) 
// 可以传递表达式结果
v.push_back(x+y)

右值引用 (rvalue reference)

定义:就是必须绑定到右值的引用,它可以指向右值,不能指向左值。c++11中右值引用可以实现“移动语义”,通过 && 获得右值引用。

右值引用绑定右值

 int&& number = 1;

错误:右值引用不能直接绑定左值

    int count = 2;
    int&& number = count;
    报错:
    error c2440: “初始化”: 无法从“int”转换为“int &&”
    message : 无法将左值绑定到右值引用

尝试让右值引用指向左值

    int count = 2;
    // 使用 std::move 把左值强制转换为右值 ,number = 2
    int&& number1 = std::move(count);
    // 等同与 std::move 类型转换 ,number = 2
    int&& number2 = static_cast<int&&>(count);
	// count = number1 = number2 = 10
	number1 = 10;

简单练习:

void test(int & o) {std::cout << "左值。" << std::endl;}
void test(int && temp) {std::cout << "右值。" << std::endl;}

int main(){
    int a;
	int && b = 10; 

	test(a);
	test(std::move(a));
	test(b);
}
结果:
a 是一个具名变量,有固定的内存地址是典型的左值。输出:"左值。"
std::move(a) 将左值 a 转换为右值引用 返回类型是 int&&。输出:"右值"
虽然 b 的类型是右值引用(int&&)但 b 本身是一个具名变量,可以取地址。 输出:"左值"

结论:右值引用类型只是用于匹配右值,而并非表示一个右值。因此,尽量不要声明右值引用类型的变量,而只在函数形参使用它以匹配右值。

浅拷贝(shallow copy)

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存(分支)。

深拷贝(deep copy)

深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象,是“值”而不是“引用”(不是分支)

编写代码:

#include <iostream>

class vector {
    int num;
    int* a;
public:
    // 构造函数
    vector(int n = 0) : num(n) {
        a = new int[num];
        for (int i = 0; i < num; ++i) {
            a[i] = i + 1;  // 初始化为1,2,3...
        }
    }

    // 析构函数
    ~vector() {
        delete[] a;
    }

    void shallowcopy(vector& v);
    void deepcopy(vector& v);

    // 打印数组内容的辅助函数
    void print() const {
        std::cout << "num = " << num << ", array content: ";
        for (int i = 0; i < num; ++i) {
            std::cout << a[i] << " ";
        }
        std::cout << std::endl;
    }

    // 修改数组内容的辅助函数
    void modify(int index, int value) {
        if (index >= 0 && index < num) {
            a[index] = value;
        }
    }
};

// 浅拷贝实现
void vector::shallowcopy(vector& v) {
    this->num = v.num;
    this->a = v.a;
}

// 深拷贝实现
void vector::deepcopy(vector& v) {
    delete[] this->a;  // 先释放原有内存
    this->num = v.num;
    this->a = new int[num];
    for (int i = 0; i < num; ++i) {
        a[i] = v.a[i];
    }
}

浅拷贝测试

int main() {
    // 测试浅拷贝
    std::cout << "=== 测试浅拷贝 ===" << std::endl;
    {
        vector v1(5);  // 创建一个包含5个元素的向量
        std::cout << "original v1: ";
        v1.print();

        vector v2(3);  // 创建另一个向量
        std::cout << "original v2: ";
        v2.print();

        v2.shallowcopy(v1);  // 浅拷贝
        std::cout << "after shallow copy, v2: ";
        v2.print();

        // 修改v1,观察v2是否变化
        v1.modify(0, 100);
        std::cout << "after modifying v1, v1: ";
        v1.print();
        std::cout << "after modifying v1, v2: ";
        v2.print();

        // 这里会崩溃,因为v1和v2都试图删除同一块内存
        std::cout << "program will crash here due to double delete\n";
    }
    }
  程序输出:
  === 测试浅拷贝 ===
original v1: num = 5, array content: 1 2 3 4 5
original v2: num = 3, array content: 1 2 3
after shallow copy, v2: num = 5, array content: 1 2 3 4 5
after modifying v1, v1: num = 5, array content: 100 2 3 4 5
after modifying v1, v2: num = 5, array content: 100 2 3 4 5
program will crash here due to double delete

崩溃位置:
    // 析构函数
    ~vector() {
        delete[] a;
    }

深拷贝测试

int main() {


    // 测试深拷贝
    std::cout << "\n=== 测试深拷贝 ===" << std::endl;
    {
        vector v1(5);
        std::cout << "original v1: ";
        v1.print();

        vector v2(3);
        std::cout << "original v2: ";
        v2.print();

        v2.deepcopy(v1);  // 深拷贝
        std::cout << "after deep copy, v2: ";
        v2.print();

        // 修改v1,观察v2是否变化
        v1.modify(0, 100);
        std::cout << "after modifying v1, v1: ";
        v1.print();
        std::cout << "after modifying v1, v2: ";
        v2.print();

        // 这里不会崩溃,因为每个对象管理自己的内存
        std::cout << "program will exit normally\n";
    }

    return 0;
} 

=== 测试深拷贝 ===
original v1: num = 5, array content: 1 2 3 4 5
original v2: num = 3, array content: 1 2 3
after deep copy, v2: num = 5, array content: 1 2 3 4 5
after modifying v1, v1: num = 5, array content: 100 2 3 4 5
after modifying v1, v2: num = 5, array content: 1 2 3 4 5
program will exit normally

再探右值引用

使用 c++ 11 的右值引用,重载拷贝函数,代码修改为:​​​​​​​

class vector {
    int num;
    int* a;
public:
    // 构造函数
    vector(int n = 0) : num(n) {
        a = new int[num];
        for (int i = 0; i < num; ++i) {
            a[i] = i + 1;  // 初始化为1,2,3...
        }
    }

    // 析构函数
    ~vector() {
        delete[] a;
    }
    
    //左值引用形参=>匹配左值
    void copy(vector& tmp) {

        if (nullptr != this->a){
            delete[] this->a;
        }
      
        this->num = tmp.num;
        this->a = tmp.a;
        
        // 防止tmp析构时删除内存
        tmp.a = nullptr;    
    }
 
   //右值引用形参=>匹配右值
    void copy(vector&& tmp) {
        this->num = tmp.num;
        this->a = tmp.a;
    }
};

调用测试

int main() {
    // 测试左值引用版本
    vector v1(5);        // v1: {1,2,3,4,5}
    vector v2;
    v2.copy(v1);        // 深拷贝:v2获得自己的内存副本

    // 测试右值引用版本
    vector v3;
    v3.copy(vector(3)); // 移动:直接窃取临时对象的资源

    return 0;
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

kotlin中const 和val的区别及使用场景分析

04-07

C++中std::distance使用方法示例

04-07

C/C++错误信息处理的常见方法及函数

04-07

c++ 函数重载的规则是什么

04-08

dev c++ 怎么添加外部库

04-08

c++ 递归函数怎么实现

04-07

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论