40人参与 • 2025-04-08 • C/C++
定义:
定义:
左值和右值主要的区别之一是左值可以被修改,而右值不能。
int number; number = 1
在这段代码中 number 为左值 ,1 为右值。
// getvalue()返回的临时值是右值 int value = getvalue();
引用的本质是别名,可以通过引用改变变量的值,传参时传引用可以避免拷贝。
定义: 引用一个对象;
基本用法:
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)
定义:就是必须绑定到右值的引用,它可以指向右值,不能指向左值。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 本身是一个具名变量,可以取地址。 输出:"左值"
结论:右值引用类型只是用于匹配右值,而并非表示一个右值。因此,尽量不要声明右值引用类型的变量,而只在函数形参使用它以匹配右值。
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存(分支)。
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象,是“值”而不是“引用”(不是分支)
编写代码:
#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; }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论