当前位置: 首页 > news >正文

c++新特性之 左右值 lambda 以及“for”

1.左值和右值

左值定义:左值是一个表达式,它表示一个占有特定内存位置的对象,并且这个对象具有可被程序访问的地址。简单来说,左值是一个可以出现在赋值语句左边的表达式,因为它代表了一个可以被

右值定义:右值是一个表达式,它代表一个临时的值,这个值不具有可被程序访问的地址,通常出现在赋值语句的右边。简单来说,右值是一个只能出现在赋值运算符右边的表达式,它不能作为赋值的目标

右值引用的定义与语法
右值引用的语法形式为T&&,其中T是数据类型。例如,int&&表示对int类型的右值引用,std::string&&表示对std::string类型的右值引用。右值引用只能绑定到右值,不能绑定到左值

左值引用
左值引用是对左值的引用,它为一个已存在的对象提供了一个别名。通过左值引用,可以使用不同的名称来访问同一个对象。左值引用使用 

int& ref = num

1.新特性

std::move:函数用于将一个左值强制转换为右值引用,从而可以触发移动语义。它本质上是一个类型转换,将对象标记为可以被移动的。

#include <iostream>
#include <utility>
#include <vector>

int main() {
    std::vector<int> vec1 = {1, 2, 3};
    std::vector<int> vec2 = std::move(vec1); // 强制移动
    std::cout << "vec1 size: " << vec1.size() << std::endl;
    std::cout << "vec2 size: " << vec2.size() << std::endl;
    return 0;
}
/*vec1 size: 0
vec2 size: 3*/

2.完美转发

完美转发允许函数模板将其参数以原始的左右值属性传递给其他函数,避免不必要的拷贝和类型转换。它结合了右值引用和 std::forward 函数来实现。

#include <iostream>
#include <utility>

void print(int& value) {
    std::cout << "Lvalue: " << value << std::endl;
}

void print(int&& value) {
    std::cout << "Rvalue: " << value << std::endl;
}

template<typename T>
void forwarder(T&& arg) {
    print(std::forward<T>(arg));
}

int main() {
    int x = 10;
    forwarder(x); // 传递左值
    forwarder(20); // 传递右值
    return 0;
}

在上述代码中,forwarder 是一个函数模板,它接受一个通用引用 T&&std::forward<T>(arg) 会根据 T 的推导结果,将 arg 以原始的左右值属性转发给 print 函数。当传递左值 x 时,调用 print(int&);当传递右值 20 时,调用 print(int&&)

2.lambda公式

内联函数是一种建议编译器在调用点直接展开函数体而不是进行常规函数调用的机制,这样可以减少函数调用的开销,提高程序的执行效率。Lambda 表达式同样具有这种特性,编译器往往会将其代码在调用处直接展开。

在c++ 内存管理系统之智能指针-CSDN博客,我们知道函数调用是存在在栈,所以会浪费时间

 int x=[capture list] (parameter list) -> return type { function body }

capture list  是捕获列表,用于指定 Lambda表达式可以访问的外部变量,以及是按值还是按引用的方式访问。捕获列表可以为空,表示不访问任何外部变量,也可以使用默认捕获模式 & 或 = 来表示按引用或按值捕获所有外部变量,还可以混合使用具体的变量名和默认捕获模式来指定不同的捕获方式。
parameter list 是参数列表,用于表示 Lambda表达式的参数,可以为空,表示没有参数,也可以和普通函数一样指定参数的类型和名称,还可以在 c++14 中使用 auto 关键字来实现泛型参数。
return type 是返回值类型,用于指定 Lambda表达式的返回值类型,可以省略,表示由编译器根据函数体推导,也可以使用 -> 符号显式指定,还可以在 c++14 中使用 auto 关键字来实现泛型返回值。
function body 是函数体,用于表示 Lambda表达式的具体逻辑,可以是一条语句,也可以是多条语句,还可以在 c++14 中使用 constexpr 来实现编译期计算

值捕获

#include <iostream>
using namespace std;

int main() {
    int num = 10;
    auto lambda = [num]() {
        num = 20;  // 修改的是捕获的副本
        cout << "lambda 内部 num: " << num << endl;
    };
    lambda();
    cout << "外部 num: " << num << endl;
    return 0;
}

引用捕获

引用捕获是指 lambda 表达式捕获外部变量的引用,这样在 lambda 表达式内部对变量的操作实际上就是对外部原始变量的操作,修改会反映到外部作用域中。

#include <iostream>
using namespace std;

int main() {
    int num = 10;
    auto lambda = [&num]() {
        num = 20;  // 修改的是外部的原始变量
        cout << "lambda 内部 num: " << num << endl;
    };
    lambda();
    cout << "外部 num: " << num << endl;
    return 0;
}

初始化捕获(C++14 引入)

初始化捕获允许在 lambda 表达式中使用初始化器来初始化一个新的捕获变量,并且可以将表达式的结果绑定到这个新变量上。这为 lambda 表达式提供了更灵活的变量捕获方式,可以处理一些复杂的情况,比如捕获临时对象或对变量进行计算后再捕获。

#include <iostream>
#include <string>
using namespace std;

int main() {
    int a = 5;
    int b = 3;
    // 初始化捕获,将 a + b 的结果捕获为新变量 sum
    auto lambda = [sum = a + b]() {
        cout << "sum: " << sum << endl;
    };
    lambda();
    return 0;
}

显式捕获

显式捕获是指在 lambda 表达式的捕获列表中明确指定要捕获的变量,包括值捕获和引用捕获。与之相对的是隐式捕获(如 [=] 表示值捕获所有外部可见变量,[&] 表示引用捕获所有外部可见变量 )。显式捕获能让代码更加清晰,明确知道 lambda 表达式依赖哪些外部变量。

#include <iostream>
using namespace std;

int main() {
    int x = 10;
    int y = 20;
    // 显式值捕获 x,显式引用捕获 y
    auto lambda = [x, &y]() {
        x = 30;  // 修改的是 x 的副本
        y = 40;  // 修改的是外部的 y
        cout << "lambda 内部 x: " << x << endl;
        cout << "lambda 内部 y: " << y << endl;
    };
    lambda();
    cout << "外部 x: " << x << endl;
    cout << "外部 y: " << y << endl;
    return 0;
}

引用隐式捕获

使用 [&] 来表示引用隐式捕获,它会以引用的方式捕获 lambda 表达式所在作用域中所有可见的变量。这意味着 lambda 表达式内部对这些变量的修改会直接影响到外部的原始变量。

#include <iostream>

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

    // 使用 [&] 进行引用隐式捕获
    auto lambda = [&]() {
        a = 100;
        b = 200;
        std::cout << "Inside lambda: a = " << a << ", b = " << b << std::endl;
    };

    lambda();
    std::cout << "Outside lambda: a = " << a << ", b = " << b << std::endl;
    return 0;
}

3.新for循环

for (declaration : range) {
    // 循环体
}
  • declaration:用于声明一个变量,这个变量会在每次循环迭代时被初始化为 range 中的一个元素。
  • range:表示一个序列,它可以是数组、std::vectorstd::liststd::string 等任何定义了 begin() 和 end() 成员函数或者可以使用 std::begin() 和 std::end() 函数的对象
#include <iostream>
#include <vector>

int main() {
    // 定义一个 std::vector
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // 使用范围 for 循环遍历 vector
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // 也可以用于遍历数组
    int arr[] = {6, 7, 8, 9, 10};
    for (int val : arr) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}

相关文章:

  • qt-C++笔记之ubuntu22.04源码安装Qt6.8.2
  • AF3 _correct_post_merged_feats函数解读
  • 解决VSCode鼠标光标指针消失
  • 分布式锁实现方案对比与最佳实践
  • 【计网】数据链路层
  • Glide图片加载优化全攻略:从缓存到性能调优
  • python官方文档阅读整理(一)
  • 2024最新版Java面试题及答案,【来自于各大厂】
  • 【ORACLE】char类型和sql优化器发生的“错误”反应
  • 【工具推荐】在线提取PDF、文档、图片、论文中的公式
  • 数字万用表的使用教程
  • 学习 Wireshark 分析 Android Netlog
  • 什么是SElinux?
  • MongoDB Chunks核心概念与机制
  • 【前端】HTML 备忘清单(超级详细!)
  • 深入探索Python机器学习算法:模型调优
  • vue3,Element Plus中抽屉el-drawer的样式设置
  • 爬虫逆向实战小记——解决captcha滑动验证码
  • linux 安装Mysql无法远程访问问题的排查
  • JavaWeb5、Maven
  • 微商城网站建设多少钱/百度百科怎么创建自己
  • 旅游网站建设课程设计报告/网站seo视频教程
  • 北京设计公司有哪些公司/seo站长网
  • 设计师常备设计网站大全/在哪里找软件开发公司
  • 中山网站建设品牌/营销型网站更受用户欢迎的原因是
  • 电商设计属于什么设计/搜索引擎优化方案案例