C++ : 仅添加一个引用& 就直接导致程序崩溃
问题描述
在项目某次开发中,测试过程中出现了coredump问题。经过asan工具检测,报了heap-use-after-free内存错误,最终定位到竟是无意中添加了一个引用&导致的!
开发时因为看到相关类访问类成员的接口函数未返回引用,而是返回了一个拷贝,因此想着要将返回值改为引用,避免多余的拷贝。例如在以下代码中,我们将GetArr函数的返回值改为引用:
class Foo {
private:
std::vector<int> arr;
public:
std::vector<int>& GetArr() { // add & for return type
return arr;
}
// other functions
};
看起来这并没什么问题,但是在多线程环境下,加一个&可能就会导致程序崩溃。
问题分析
比如以下代码展示了一个简单的例子,表面看起来GetArr是有锁保护的,但实际上锁保护被打破了:
class Foo {
private:
std::vector<int> arr;
std::mutex mut;
public:
std::vector<int>& GetArr() {
std::lock_gurad<std::mutex> lk(mut);
return arr;
}
// other functions
};
为什么呢?GetArr返回一个 vector 的引用,然后立即释放锁。因此,返回的引用可以在没有任何保护的情况下被修改。当多个线程对同一个Foo实例的arr进行读写时,就会导致数据竞争,从而导致程序崩溃的风险。
如何避免?
对于类对象的多线程共享数据,接口应返回拷贝而不是引用。
std::vector<int> GetArr() { // return a copy
return arr;
}
总结
再翻翻《C++并发实战》,才发现书中早已经总结了这个陷阱:
通常来说,类的所有成员函数在访问任何数据成员之前,假如都先对互斥加锁,并在完成访问后解锁,共享数据就可很好地受到全方位保护。可惜事与愿违:如果类的成员函数返回指向共享数据的指针或引用,那么这些数据就会在锁外被访问,从而破坏了互斥的效果。
因此,我们可以总结一个简单的规则:不得向锁所在的作用域之外传递指针和引用,指向受保护的共享数据,无论是通过函数返回值将它们保存到对外可见的内存,还是将它们作为参数传递给使用者提供的函数。
参考
- C++ Concurrency in Action, Anthony Williams
你好,我是七昂,致力于分享C++、计算机底层、机器学习等系列知识。希望我们能一起探索程序员修炼之道。如果我的创作内容对您有帮助,请点赞关注。如果有问题,欢迎随时与我交流。感谢你的阅读。
知乎、公众号:七昂的技术之旅
C++ : 仅添加一个引用& 就直接导致程序崩溃的更多相关文章
- WPF 线程中异常导致程序崩溃
一般我们WPF中都加全局捕获,避免出现异常导致崩溃. Application.Current.DispatcherUnhandledException += Current_DispatcherUnh ...
- 解决Qt中QTableWidget类方法setItem 时导致程序崩溃问题
在为一个音乐播放器增加功能时莫明奇妙的出现程序崩溃,定位到是由于QTableWidget 的setItem方法导致的,最终在此处找到了解决方式. 大致是说不能在setItem之前连接cellChang ...
- c# Linq Where 抛出异常 导致 程序崩溃
Collection was modified; enumeration operation may not execute" 这次项目中遇到一个问题, 就是C#程序随机崩溃, 抛出上面的异 ...
- setSupportActionBar(toolbar)导致程序崩溃闪退
最近在做一个项目,使用了第三方的开源项目,主要是想实现android5.0之后推出的MaterialDesign的风格,但是代码已经写好了,发现一运行就闪退,所以就开始debug,发现问题出现在 To ...
- Visual Stdio 无法直接启动带有“类库输出类型”的项目若要调试此项目,请在此解决方案中添加一个引用库项目的可执行项目。将这个可执行项目设置为启动项目!
j解决方法:项目-属性-应用程序-输出类型-Windows应用程序
- 创建一个MVC解决方案,添加一个控制器后,运行程序报错:”/"未找到服务器
1.创建一个MVC项目,如图
- SDWebImage 加载一些大的图片的时候导致程序崩溃
在 UIImage+MultiFormat这个类里面添加如下压缩方法, +(UIImage *)compressImageWith:(UIImage *)image { float imageWid ...
- Android While 循环导致的资源占用过高进而导致程序崩溃问题
Timeline: Activity_launch_request time:6562004-14 15:31:25.347: I/dalvikvm(3483): Total arena pages ...
- 解决IIS应用程序池默认回收导致程序崩溃
这些网上常见的解决: 其实他们只知其一不知其二:一味的调长超时时间根本就是治标不治本的解决方案, 超时时间再长也会出现到期时间,那时候我们该怎么办呢?(某些吃瓜群众就会大喊:那我就手动去重启一下呗 ...
- 综合经验:IO读写错误必然导致程序崩溃
仿佛是忽然间产生的问题,每次程序退出时候,必然崩溃,花了整整一天才找到原因,就是对数据库的IO读写错误.主要是因为析构函数调用了Disconnect函数,内容如下: void SFTPTool::Di ...
随机推荐
- 虚拟 DOM 实现原理?
虚拟 DOM 的实现原理主要包括以下 3 部分: 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象: diff 算法 - 比较两棵虚拟 DOM 树的差异: pach 算法 ...
- css浅谈Flex布局
1.打开Flex布局 .box{ display: flex; } 2.容器的属性 flex-direction flex-wrap flex-flow justify-content align-i ...
- 推荐几款个人喜欢的IDEA开发工具主题【更舒适的开发】
IDEA,全称 IntelliJ IDEA ,是Java语言的集成开发环境,IDEA在业界被公认为是最好的 java 开发工具之一,尤其在智能 代码助手.代码自动提示.重构.J2EE支持. Ant . ...
- tp5生命周期
https://www.kancloud.cn/manual/thinkphp5/118011 1.入口文件 用户发起的请求都会经过应用的入口文件,通常是 public/index.php文件.当然, ...
- Django DRF @action 装饰器
@action 装饰器在Django REST Framework (DRF) 中非常有用,它可以帮助你在ViewSet中创建自定义的动作,而不仅仅是依赖标准的CRUD操作(Create, Read, ...
- [oeasy]python0123_中文字符_文字编码_gb2312_激光照排技术_王选
中文编码GB2312 回忆上次内容 上次回顾了 日韩各有 编码格式 日本 有假名 五十音 一字节 可以勉强放下 有日本汉字 字符数量超过20000+ 韩国 有谚文 数量超过500 一个字节 ...
- [oeasy]python0036_牛说_cowsay_小动物说话_asciiart_figlet_lolcat_管道(祝大家新年快乐~)
牛说(cowsay) 回忆上次内容 上次我们研究了shell脚本的编程 并且在shell中实现了 循环语句 延迟命令 清屏命令 python命令 figlet命令 编辑 还能整点什么呢? 还想 ...
- 机器学习:详解多任务学习(Multi-task learning)
详解多任务学习 在迁移学习中,步骤是串行的,从任务\(A\)里学习只是然后迁移到任务\(B\).在多任务学习中,是同时开始学习的,试图让单个神经网络同时做几件事情,然后希望这里每个任务都能帮到其他所有 ...
- 【SpringMVC】 Controller接收深度复杂对象封装不到的问题
首先来看数据结构的定义: 一个Form对象,然后里面有一个排版日期对象的List集合 排班集合的每个元素中又有一个String集合 在前端的Post请求中可以看到这个String集合是传递了的 但是D ...
- 【Java】Reflection 反射机制 01概述
Reflection 反射机制 反射允许程序在执行期间借助ReflectionAPI获取任何类的内部信息,直接操作任意对象的内部属性和方法 加载完类之后,堆内存的方法区产生了一个Class 类类型的对 ...