C++ lambda按引用捕获导致的空悬指针问题

lambda可以按值捕获,也可以按引用捕获。按引用捕获会导致闭包包含指涉到局部变量的引用,或者指涉到定义lambda式的作用域内形参的引用。一旦lambda式所创建的闭包越过了该局部变量或者形参的生命周期,那么闭包内的引用就会空悬。比如下面这段code:

using FilterContainer = vector<function<bool(int)>>;
FilterContainer filters;void addDivisiorFilter() {auto divisor = computeDivisor(calc1, calc2);filters.emplace([&](int val) { return val % divisor == 0; });
}

lambda指涉到局部变量divisor的引用,该变量在addDivisiorFilter返回时就不复存在,导致引用(指针)空悬。如果改用显式引用捕获[&divisor],问题依旧但是显式列出lambda所依赖的局部变量或者形参是更好的软件工程实践。如果使用按值捕获,那么问题得到解决:

void addDivisiorFilter() {auto divisor = computeDivisor(calc1, calc2);filters.emplace([=](int val) { return val % divisor == 0; });
}

指针也是一种变量,当指针作为形参时,有以下将类成员函数指针移入闭包,生成保存任何类型的函数的闭包操作:

template<typename Ro=void>
struct CommCommand {
private:function<Ro()> m_f;
public:template<class R, class C, class... DArgs, class P, class... Args>void Wrap(R(C::*f)(DArgs...) const, P&& p, Args&&... args) {cout << "bind const member func" << endl;m_f = [&, f]{return (*p.*f)(args...);};}template<class R, class C, class... DArgs, class P, class... Args>void Wrap(R(C::*f)(DArgs...), P&& p, Args&&... args) {cout << "bind member func" << endl;//m_f = [f, p, args...]{ return (*p.*f)(args...); };	//okm_f = [&] {return ((*p).*f)(args...);};}Ro Execute() {return m_f();}
};struct stA {int m_a;const int triple2(int a) const {return m_a * 3 + a;}void triple3() {cout << "triple3" << endl;}
};void TestWrap() {CommCommand<int> cmd;stA t = { 10 }, int x = 3;cmd.Wrap(&stA::triple2, &t, 3);cmd.Execute();CommCommand<> cmd1;cmd1.Wrap(&stA::triple3, &t);cmd1.Execute();	//crash, if no val capture with f
}

类CommCommand希望能通过Wrap()包装任何类成员函数为CommCommand的成员变量function<void()> m_f,需要执行所包装函数的时候调用Execute()。该Wrap也有const版本和非const版本的重载,const版本在捕获类成员函数的指针时,对其用了按值捕获[&, f](即cmd),而非const版本在捕获类成员函数的指针时,对其默认用了按引用捕获[&](即cmd1)。

在执行cmd.Execute()是没有问题,而执行cmd1.Execute()发生了crash,通过debug发现按引用捕获类成员函数指针,在Wrap()的时候可以取到类成员函数的地址,但一旦退出Wrap(),该类成员函数的地址不复存在。
以下是cmd在执行Wrap()、Execute()时,lambda内部所保存的类对象地址类成员函数的地址的情况:

 

下面是cmd1在执行Wrap()、Execute() 时,lambda内部所保存的类对象地址类成员函数的地址的情况:

 可以看到,cmd1如若按引用捕获类成员函数的地址,lambda内部所保存的指针f的内容已经失效(变成了类对象起始地址+48byte,为啥会如此原因尚不能确定)。也就是说,类成员函数的地址作为形参被纳入闭包时,一旦赋值闭包的语句结束,其形参也就失效了,希望用引用指向该形参的意图无法达成。虽说类成员函数的地址本身是确定的,其地址类似于在类外一个静态的区域,需要和类对象地址一起使用。但是lambda只能捕获局部变量,故这里将成员函数的地址作为形参。

因此,lambda对于指针的捕获应引起谨慎,如果不希望修改其指针,而仅仅是使用该指针,如解引用等,按值捕获为好。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/43005.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

给您介绍工控CAN总线

CAN是什么 CAN&#xff0c;全称Controller Area Network&#xff0c;即控制器局域网&#xff0c;是一种由Bosch公司在1983年开发的通信协议。它主要用于汽车和工业环境中的电子设备之间的通信。CAN协议定义了物理层和数据链路层的通信机制&#xff0c;使得不同的设备能够通过CA…

家里猫咪浮毛太多怎么办?值得买的猫毛空气净化器推荐

作为一位拥有5年铲屎经验的铲屎官&#xff0c;我知道许多新手铲屎官可能听说过宠物空气净化器&#xff0c;但了解得不多。事实上&#xff0c;宠物空气净化器确实是养猫家庭必备的小家电之一。它的大面积进风口可以有效吸附空气中的微小浮毛和皮屑&#xff0c;专门的除臭技术能有…

写一个函数,返回参数二进制中 1 的个数

代码要求 输入一个整数n&#xff0c;输出该数32位二进制中为1的个数&#xff08;包括最高位的符号位&#xff09;&#xff0c;其中负数用补码表示 如&#xff1a;输入&#xff1a;15 &#xff08;15的二进制表示&#xff1a;0000 1111&#xff09; 输出&#xff1a;4 代码实…

【server】1、后台基础搭建

1、父工程创建 1.1新建 1.2 父工程pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"h…

电脑选购全解析!你需要知道的一切!

在选择电脑类型时&#xff0c;你可以考虑以下因素&#xff1a; 你的主要用途是什么&#xff1f; 你是否需要携带电脑&#xff1f; 你的预算是多少&#xff1f; 你对性能和图形要求有多高&#xff1f; 你是否需要特定的软硬件功能&#xff1f;根据这些因素&#xff0c;你可以…

Git秘籍大公开:从基础概念到高级技巧的全面解析

文章目录 前言一、Git基础介绍1. 作用2. 为什么要进行源代码管理?3. Git的诞生4. Git管理源代码特点5. Git操作流程图解 二、工作区暂存区和仓库区介绍1. 工作区2. 暂存区3. 仓库区 三、Git单人本地仓库操作1. 安装git2. 查看git安装结果3. 创建项目4. 创建本地仓库5. 配置个人…

SpringCloud 负载均衡

目录 一、负载均衡 1、问题 2、什么是负载均衡 服务端负载均衡 客户端负载均衡 二、Spring Cloud LoadBalance 1、使用 Spring Cloud LoadBalance 2、负载均衡策略 3、LoadBalancer 原理 一、负载均衡 1、问题 我们来看一下前面写的代码&#xff1a; List<Serv…

电子版盖章怎么弄(电子版公章怎么盖上)

下面是利用e章宝盖电子公章更简单&#xff0c;从印章库中选中要盖的公章&#xff0c;然后在文档中想要盖的位置单击一下即可&#xff1a; 第一步&#xff1a;制作需要盖的电子印章 一般是先扫描公章&#xff0c;然后使用e章宝的一键抠章功能&#xff0c;把印章导入到印章库中…

音频demo:使用fdk-aac将PCM数据编码成aac数据

1、README a. 编译 编译demo 本demo是使用的开源项目fdk-aac将PCM数据编码成aac音频文件。由于提供的.a静态库是在x86_64的机器上编译的&#xff0c;所以默认情况下仅支持该架构的主机上编译运行。 $ make编译fdk-aac&#xff08;可选&#xff09; 如果想要在其他架构的CP…

Java语言程序设计——篇二(1)

Java语言基础 数据类型关键字与标识符关键字标识符 常量与变量1、常量2、变量 类型转换自动类型转换强制类型转换 数据类型 数据的基本要素数据的性质&#xff08;数据结构&#xff09;数据的取值范围&#xff08;字节大小&#xff09;数据的存储方式参与的运算 Java是一门强类…

常见的自动化工具开发必备的源代码!

随着科技的飞速发展&#xff0c;自动化工具已经成为我们日常工作中不可或缺的一部分&#xff0c;自动化工具不仅极大地提高了工作效率&#xff0c;还降低了人为错误的可能性。 然而&#xff0c;要想开发出高效、稳定的自动化工具&#xff0c;掌握一些常见的源代码技巧是至关重…

vue中一周的时间选择多个阶段(手动表格选择)

先给大家看一下效果图 源代码 <template><div style"width: 45%"><div style"width: 100%"><div class"time"><div class"timeleft">星期/时间</div><div class"timeright"><…

FastAPI是一个现代、快速(高性能)的Web框架

FastAPI是一个现代、快速&#xff08;高性能&#xff09;的Web框架&#xff0c;专门用于构建基于Python的API。以下是对FastAPI的详细介绍&#xff1a; 一、基本概述 定义与用途&#xff1a;FastAPI是一个开源项目&#xff0c;基于Starlette和Pydantic库构建而成&#xff0c;…

奇安信20240513笔试

题目一 解题思路 n转为字符串&#xff0c;如果位数为偶数&#xff0c;取前一半设为x&#xff0c;后一段为y&#xff0c;从x最低位开始&#xff0c;9&#xff0c;9*10&#xff0c;9*10*10。。。 到最高位&#xff0c;加x&#xff0c;如果x大于或等于y&#xff0c;加1. 位数为奇数…

linux固定主机ip

1.查看虚拟网络配置 NAT设置&#xff1a; 2.修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33 TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no" BOOTPROTO"static" DEFROUTE"yes" IPV4_FAILURE_FATAL…

idea导入opencv和mediapipe

1.参考pycharm导入cv2_pycharm import cv2-CSDN博客 2.pip install opencv-python 3. python 3.8导入mediapipe 3.1 pip install mediapipe 导入报错&#xff0c; 3.2离线导入 参考Win10安装mediapipe的步骤_mediapipe安装python版本-CSDN博客 首先安装opencv-contrib-py…

App UI性能测试 - PerfDog使用全教程

App 性能测试指标: 响应、内存、CPU、FPS、GPU渲染、耗电、耗流等。 PerfDog的性能数据更加全面,所以下面以PerfDog来介绍安装使用流程及测试数据的获取与分析。 官网: PerfDog | 全平台性能测试分析专家 第一步,先访问官网进行注册, 注册好账号后,点击下载PerfDog,下…

git 文件没有修改,但一直提示有0行改动,还原也不行

查看文件修改内容 原来是文件的模式(读写可执行权限)发生了变化,内容本是没有变化. 怎么解决 git config --add core.filemode false忽略文件模式

Vue90-Vuex模块化:namespace

一、模块化的目标 当业务很复杂的时候&#xff0c;各个模块中的内容会很多&#xff0c;所以&#xff0c;要将不同业务功能的模块放到不同的位置 二、实现 2-1、模块内容的拆分 将对应的模块的内容&#xff0c;添加到对应的对象中去。 2-2、拆分后模块的使用 1、方式一 2、方…

创建react的脚手架

Create React App 中文文档 (bootcss.com) 网址&#xff1a;creat-react-app.bootcss.com 主流的脚手架&#xff1a;creat-react-app 创建脚手架的方法&#xff1a; 方法一&#xff08;JS默认&#xff09;&#xff1a; 1. npx create-react-app my-app 2. cd my-app 3. …