MickeyMiao

起点草甸

MickeyMiao

code is cheap, show me your prompt

51 篇文章 · 18 个分类 · 4 位朋友

向下滑动,出发 (或按 1-6 直达)

服务器小镇

家里小主机上的 Minecraft 生存服,白名单制。加入:QQ 群

状态
读取中…
在线
-
版本
-
已开服
-

每 10 分钟更新一次

关于雪松林

嗨,我是王思淼

图形渲染开发工程师 @ 小米。喜欢图形学、游戏和折腾服务器。

完整介绍 GitHub Bilibili Steam

回到森林 Esc 关闭

笔记C++

C++ 左值与右值 左值引用与右值引用

左值与右值

int a = 10; // a是左值, 10是右值
int *p = &a; // *p是左值, &a是右值
*p = 20; 

左值: 表示某个特定内存位置的表达式

  • 可以被赋值(可以出现在赋值号的左边和右边)
  • 有明确的内存地址
  • 例如: int a = 10; 中的a是左值

右值: 不能被赋值的表达式

  • 不能出现在赋值号的左边
  • 临时变量
  • 例如: int a = 10; 中的10是右值

++i: i是左值, 返回的是自增之后的变量本身, 可以被赋值 i++: i是右值, 返回的是自增之前的变量, 不能被赋值

左值引用与右值引用

int a = 10;
int& b = a;

左值引用: int& b = a;

  • b是左值引用, a是左值
  • 这里引用的a需要在之前已经定义过, 且a是左值, 即之前有: int a = 10;
int&& c = 10;

右值引用: int&& a = 10;

  • 这里引用的10是右值, 可以是临时变量
  • 取右值引用时, 会先用一个临时变量保存右值, 然后将这个临时变量的地址赋给右值引用

右值本来是没有地址的, 但是编译器会通过临时变量保存右值, 可以取到这个临时变量的地址, 然后将这个地址赋给右值引用

#include <iostream>

int Handle(int& l) {} // 接受左值引用
int Handle2(int&& r) {} // 接受右值引用

int main(){
    int a = 10;
    Handle(a); // 调用Handle函数, 传入的是左值
    Handle(10); // 编译错误, 传入的是右值, 但是Handle函数需要的是左值
    Handle2(10); // 调用Handle2函数, 传入的是右值
    Handle2(a); // 编译错误, 传入的是左值, 但是Handle2函数需要的是右值
}

左值引用与右值引用的意义

右值有一个特殊的性质, 就是基本上只会被使用一次, 对于这种只会被使用一次的右值, 如果是比较大的数据(例如一个很大的数组), 如果用左值引用, 那么会拷贝一份数据, 但是如果用右值引用, 那么只会拷贝一个地址, 节省了内存

#include <iostream>
#include <vector>

// 函数重载分别接受左值引用和右值引用
void Process(const std::vector<int>& v) {
    std::cout << "Left value reference\n";
}
void Process(std::vector<int>&& v) {
    std::cout << "Right value reference\n";
    // 在这里可以直接操作 v 的资源,而不拷贝
}

int main() {
    std::vector<int> v = {1, 2, 3};
    Process(v);             // 调用左值版本
    Process(std::move(v));  // 调用右值版本
}

使用 std::move 将 v 转化为右值, 从而调用右值引用版本的函数, 这样就可以直接操作 v 的资源, 而不拷贝

#C++#左值#右值#左值引用#右值引用

评论