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

lambda 表达式与mutable

目录

  • 1. mutable 关键字表示lambda表达式可以修改捕获的变量
  • 2. mutable 与 捕获引用的区别: mutable 复制了外部变量,然后对其修改。 捕获引用:直接修改外部变量
  • 3. lambda 表达式底层实现原理
    • 3.1 Functor func 这个调用的哪个构造器呢

1. mutable 关键字表示lambda表达式可以修改捕获的变量

你给出的代码片段展示了C++11 lambda表达式的使用,其中包含了一个捕获列表和一个函数体。让我们逐行解释一下:

int id = 0;
auto func = [id]()mutable {
    std::cout << "id:" << id << std::endl;
    ++id; // 对的,可以修改
};


 1. int id = 0;:定义一个整型变量id并初始化为02. auto func = [id]()mutable { ... };* auto关键字表示函数的返回类型将由编译器自动推断。
    * [id]是捕获列表,它告诉编译器这个lambda表达式捕获了外部变量id。
    * ()表示这是一个无参数的函数。
    * mutable关键字表明这个lambda表达式可以修改捕获的变量。这在需要修改捕获变量的情况下非常有用。

 3. std::cout << "id:" << id << std::endl;:在控制台输出id:和当前的id值。

 4. ++id;:对id进行前置递增操作。

这个lambda表达式创建了一个可以访问和修改id变量的函数对象。每次调用这个函数时,它会输出当前的id值,并将id递增1。由于使用了mutable关键字,lambda表达式可以修改捕获的变量id。

"mutable"这个词在英语中意味着“可变的”。在C++中,mutable关键字用于修饰捕获的变量,使得lambda表达式或函数可以修改这些变量的值。通常情况下,lambda表达式捕获的变量是不可变的,使用mutable关键字可以破坏这种不可变性,允许对捕获变量进行修改。

例如:

int x = 0;
auto lambda = [x]() mutable {
    x++;
    std::cout << "x: " << x << std::endl;
};
lambda(); // 输出 "x: 1"
lambda(); // 输出 "x: 2"

在这个例子中,x是被捕获的变量,mutable关键字使得lambda表达式可以修改x的值。每次调用lambda函数时,x的值都会增加1。

2. mutable 与 捕获引用的区别: mutable 复制了外部变量,然后对其修改。 捕获引用:直接修改外部变量

在C++中,mutable关键字和引用捕获方式(&)有不同的用途和效果,它们可以在某些情况下结合使用,但它们的基本功能和影响是不同的。下面详细解释一下它们之间的区别:

  • MUTABLE 关键字

mutable关键字用于修饰捕获的变量,使得lambda表达式或函数可以修改这些变量的值。它主要用于捕获的常量引用或常量值的情况。使用mutable关键字可以让lambda表达式或函数修改捕获变量的值。

int x = 0;
auto lambda = [x]() mutable {
    x++;
    std::cout << "x: " << x << std::endl;
};
lambda(); // 输出 "x: 1"
lambda(); // 输出 "x: 2"

在这个例子中,x是被捕获的变量,mutable关键字使得lambda表达式可以修改x的值。

  • 引用捕获(&)

引用捕获方式允许lambda表达式或函数直接修改外部变量的值,而不需要创建变量的副本。这在需要修改外部变量时非常有用,尤其是当外部变量的类型是昂贵或不可变的对象时。

int x = 0;
auto lambda = [&x]() {
    x++;
    std::cout << "x: " << x << std::endl;
};
lambda(); // 输出 "x: 1"
lambda(); // 输出 "x: 2"

在这个例子中,x是通过引用捕获的,这意味着lambda表达式直接修改了外部变量x的值。

结合使用 MUTABLE 和引用捕获

你可以在同一个lambda表达式中结合使用mutable关键字和引用捕获。例如:

int x = 0;
auto lambda = [&x]() mutable {
    x++;
    std::cout << "x: " << x << std::endl;
};
lambda(); // 输出 "x: 1"
lambda(); // 输出 "x: 2"

在这个例子中,x既是通过引用捕获的,也是mutable关键字作用的对象。这意味着lambda表达式可以修改x的值,同时也可以修改捕获变量本身(如果有的话)。

总结

  • mutable关键字用于修改捕获的变量值。
  • 引用捕获(&)用于直接修改外部变量的值。
  • 它们可以在某些情况下结合使用,但它们的基本功能和影响是不同的。

3. lambda 表达式底层实现原理

你给出的代码展示了如何使用C++中的结构体(struct)来创建一个函数对象(Functor),这个函数对象捕获并修改了外部变量id。下面是对代码的逐行解释:

struct Functor {
public:
    void operator()() {
        std::cout << "id:" << id << std::endl;
        ++id; // 对的,可以修改
    }
private:
    int id; // 拷贝了外部的id变量值
};
Functor func;


 1. struct Functor { ... }:定义了一个名为Functor的结构体。

 2. void operator()():这是一个函数对象的函数调用运算符,它定义了如何调用Functor对象。每次调用func()时,都会执行这个函数体。

 3. std::cout << "id:" << id << std::endl;:在控制台输出id:和当前的id值。

 4. ++id;:对id进行前置递增操作。

 5. private: int id;:id是Functor结构体的一个私有成员变量,它被初始化为外部变量id的值。每个Functor对象都有自己独立的id副本,这意味着修改id不会影响外部的id变量,除非显式地传递外部变量的引用或指针。

 6. Functor func;:创建了一个Functor对象func。这个对象拥有自己的id副本,初始值为外部变量id的值。


使用外部变量

如果你希望Functor对象能够修改外部变量id,你需要将外部变量传递给Functor对象,通常通过引用或指针。例如:

int id = 0;
Functor func;

void callFunctor() {
    func(id); // 传递外部变量id的引用
}

void someFunction() {
    callFunctor();
    // id 现在是 1
}

在这个例子中,func(id)将外部变量id的引用传递给Functor对象func,这样func就可以直接修改id的值。

3.1 Functor func 这个调用的哪个构造器呢

在C++中,结构体(struct)和类(class)都有默认的构造器,它们会初始化所有的成员变量。对于你给出的代码:

struct Functor {
public:
    void operator()() {
        std::cout << "id:" << id << std::endl;
        ++id;
    }
private:
    int id;
};
Functor func;

当你创建Functor对象func时,id成员变量会被默认初始化为0。因此,Functor func;这一行代码实际上调用的是Functor构造器,它初始化id成员变量为0。

默认构造器

对于Functor结构体,C++会自动为它生成一个默认构造器,该构造器不接受任何参数,并且会初始化所有未显式初始化的成员变量。因此,Functor func;调用的是这个默认构造器,它会将id成员变量初始化为0。

显式构造器

如果你希望显式地定义构造器,可以这样做:

struct Functor {
public:
    Functor(int _id) : id(_id) {} // 显式构造器
    void operator()() {
        std::cout << "id:" << id << std::endl;
        ++id;
    }
private:
    int id;
};

Functor func(10); // 调用显式构造器,初始化id为10

在这个例子中,我们定义了一个显式的构造器Functor(int _id) : id(_id) {},它接受一个int参数并将其赋值给id成员变量。然后我们使用Functor func(10);调用这个构造器,初始化id为10。


http://www.kler.cn/a/399458.html

相关文章:

  • Qt 之 qwt和QCustomplot对比
  • 3步实现贪吃蛇
  • 论文笔记 SuDORMRF:EFFICIENT NETWORKS FOR UNIVERSAL AUDIO SOURCE SEPARATION
  • 树莓派4B Qt+FFMPEG 多线程录制USB相机mjpeg数据流“h264_omx“硬件编码的MP4文件
  • Python_爬虫3_Requests库网络爬虫实战(5个实例)
  • torchvision库在进行图片转换操作中报antialias参数没有显式设置会导致不同图片后端中的值不统一的警告信息
  • 【Golang】——Gin 框架中的模板渲染详解
  • 省级金融发展水平数据(2000-2022年)
  • hive中windows子句的使用
  • UEFI学习笔记(十六):edk2子目录常用驱动介绍
  • Redis 内存管理
  • UNIX网络编程-TCP套接字编程(实战)
  • Amazon Web Services (AWS)
  • Linux第四讲:Git gdb
  • 数学建模问题攻略指南
  • XXL-JOB相关面试题
  • 【第四课】rust声明式宏理解与实战
  • FFmpeg 4.3 音视频-多路H265监控录放C++开发十三.2:avpacket中包含多个 NALU如何解析头部分析
  • 算法——有序数组的平方(leetcode977)
  • 力扣第 55 题 跳跃游戏
  • 大语言模型通用能力排行榜(2024年11月8日更新)
  • 项目技术栈-解决方案-注册中心
  • JavaSE常用API-日期(计算两个日期时间差-高考倒计时)
  • Android 删除设置的WLAN偏好选项菜单,即设置不可见
  • 【PHP】ThinkPHP基础
  • [NSSCTF Round#16 Basic]了解过PHP特性吗 详细题解