C++-空指针调用不会引起crash

以前存在一个误解,只要是对空指针访问就会引起程序崩溃,实际上却不是,如下代码:

#include <iostream>class A
{
public:void func(){std::cout << "call func" << std::endl;int a = n; // 注释本行不会程序崩溃}
private:int n = 1;
};int main()
{A* pa = nullptr;A* pb = nullptr;A& ra = *pa;ra.func();pb->func();return 0;
}

将ra引用绑定到对pa的取值上和调用func都可以正常执行,不会导致崩溃,这是因为真正导致崩溃的原因在于对空指针内部成员变量的访问,即对this的访问,而非空指针本身,类方法是类的一部分,而非对象的一部分。我们可以利用vs的反汇编功能从汇编代码的角度理解这件事情:

    A* pa = nullptr;
00DE25F5  mov         dword ptr [pa],0  A* pb = nullptr;
00DE25FC  mov         dword ptr [pb],0  A& ra = *pa;
00DE2603  mov         eax,dword ptr [pa]  
00DE2606  mov         dword ptr [ra],eax  ra.func();
00DE2609  mov         ecx,dword ptr [ra]  
00DE260C  call        A::func (0DE135Ch)  pb->func();
00DE2611  mov         ecx,dword ptr [pb]  
00DE2614  call        A::func (0DE135Ch)  return 0;
00DE2619  xor         eax,eax  
}

可以看到对方法的调用跳转的位置是一样的,这证明了类方法是类的一部分而非对象的一部分,调用后走到0DE135Ch

00DE135C  jmp         A::func (0DE24D0h)  

紧接着又跳到0DE24D0h

class A
{
public:void func(){
00DE24D0  push        ebp  
00DE24D1  mov         ebp,esp  
00DE24D3  sub         esp,0D8h  
00DE24D9  push        ebx  
00DE24DA  push        esi  
00DE24DB  push        edi  
00DE24DC  push        ecx  
00DE24DD  lea         edi,[ebp-18h]  
00DE24E0  mov         ecx,6  
00DE24E5  mov         eax,0CCCCCCCCh  
00DE24EA  rep stos    dword ptr es:[edi]  
00DE24EC  pop         ecx  
00DE24ED  mov         dword ptr [this],ecx  // this 赋值
00DE24F0  mov         ecx,offset _1A2CA9B9_源@cpp (0DEF029h)  
00DE24F5  call        @__CheckForDebuggerJustMyCode@4 (0DE1384h)  std::cout << "call func" << std::endl;
00DE24FA  mov         esi,esp  
00DE24FC  push        offset std::endl<char,std::char_traits<char> > (0DE103Ch)  
00DE2501  push        offset string "call func" (0DE9B30h)  
00DE2506  mov         eax,dword ptr [__imp_std::cout (0DED0D4h)]  
00DE250B  push        eax  
00DE250C  call        std::operator<<<std::char_traits<char> > (0DE11A9h)  
00DE2511  add         esp,8  
00DE2514  mov         ecx,eax  
00DE2516  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0DED0A0h)]  
00DE251C  cmp         esi,esp  
00DE251E  call        __RTC_CheckEsp (0DE128Fh)  int a = n;
00DE2523  mov         eax,dword ptr [this]  
00DE2526  mov         ecx,dword ptr [eax]  
00DE2528  mov         dword ptr [a],ecx  }

00DE24ED指令把this指针赋值为了0,后面std调用部分并没有用到this指针,只是再次跳到了另一个函数执行输出字符串的功能,因此不会造成崩溃。如果写了int a = n;,汇编对应的代码将会基于0地址取对象中的n的值,此时才会造成崩溃。
注意:在C++中对nullptr的访问是undefined behavior,虽然大多数时候实际不会造成崩溃,但我们不能依赖这种未定义的行为,因为它可能崩溃也可能不崩溃,跟编译器也有关系,还是应判断空指针,避免这种情况发生。

参考:

  1. https://stackoverflow.com/questions/49872721/why-calling-function-with-nullptr-does-not-crash-my-application
  2. https://stackoverflow.com/questions/5431420/why-doesnt-the-program-crash-when-i-call-a-member-function-through-a-null-point

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

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

相关文章

ppt转换成pdf文件

最近用到了&#xff0c;记一下&#xff1b; ppt转pdf分为两种情况: 小于2007版本的 .ppt格式&#xff08;2003&#xff09; 与大于2007版本的 .pptx格式&#xff08;2007&#xff09; .ppt格式为 二进制文件 .pptx格式为xml格式&#xff0c;在java中有不同的jar包需要使用 引入…

uniapp踩坑之项目:使用过滤器将时间格式化为特定格式

利用filters过滤器对数据直接进行格式化&#xff0c;注意&#xff1a;与method、onLoad、data同层级 <template><div><!-- orderInfo.time的数据为&#xff1a;2023-12-12 12:10:23 --><p>{{ orderInfo.time | formatDate }}</p> <!-- 2023-1…

QList简单使用

1.插入 头插&#xff1a; QList<int> list {2, 3, 4}; list.prepend(1); // 在头部插入元素1尾插&#xff1a; list.append(5); // 在尾部插入元素5 中间插&#xff1a; QList<int> list {1, 2, 4, 5}; list.insert(2, 3); // 在索引为2的位置插入元素3list…

springboot 集成Dubbo2.7.8 ,连接zookeeper 提示错误 zookeeper not connected

Dubbo 连接zookeeper时&#xff0c;提示“zookeeper not connected” java.lang.IllegalStateException: zookeeper not connectedat org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient.<init>(CuratorZookeeperClient.java:83) ~[dubbo-2.7.8.jar:2.…

MySQL5 和 MySQL8 的配置区别 一些注意事项

1、使用命令行查看MySQL的版本 先保证你的mysql正在运行&#xff0c;假如用户名是root&#xff0c;密码是123456&#xff0c;运行下边的代码可以查看mysql的版本号。 mysql -uroot -p123456这里我的版本是5.7.19。也就是5版本的。 2、不同版本对应的数据库驱动jar包&#x…

Object Detection in 20 Years: A Survey(2019.5)

文章目录 Abstract1. Introduction1.1. Difference from other related reviews1.2. Difficulties and Challenges in Object Detection 2. OBJECT DETECTION IN 20 YEARS2.1. 目标检测路线图2.1.1. 里程碑:传统探测器&#xff08;粗略了解&#xff09;2.1.2. 里程碑:基于CNN的…

朴素贝叶斯

朴素贝叶斯 朴素贝叶斯理论贝叶斯决策理论条件概率全概率公式贝叶斯公式朴素贝叶斯 言论屏蔽新浪新闻分类朴素贝叶斯算法的优缺点 朴素贝叶斯算法是一种基于贝叶斯定理的有监督的机器学习算法&#xff0c;解决的是分类问题&#xff0c;如文本分类、垃圾邮件过滤、客户是否流失&…

机器学习实验三:支持向量机模型

系列文章目录 机器学习实验一&#xff1a;线性回归机器学习实验二&#xff1a;决策树模型机器学习实验三&#xff1a;支持向量机模型机器学习实验四&#xff1a;贝叶斯分类器机器学习实验五&#xff1a;集成学习机器学习实验六&#xff1a;聚类 文章目录 系列文章目录一、实验…

深入理解Java中高级使用方式四舍五入

引言 在Java编程中&#xff0c;四舍五入是一个常见的数学运算需求。虽然我们熟悉基础的Math.round()方法&#xff0c;但在一些特殊场景下&#xff0c;比如金融计算或精度要求较高的情况下&#xff0c;我们需要更深入地理解Java中的高级使用方式。本文将深入探讨使用BigDecimal…

CFS三层靶机内网渗透

CFS三层靶机内网渗透 一、靶场搭建1.基础参数信息2.靶场搭建2.1网卡配置2.2Target1配置2.2.1 网卡配置2.2.2 Target1 BT配置 2.3Target2配置2.3.1 网卡配置2.3.2 Target2 BT配置 2.4Target3配置 二、内网渗透Target11.1信息收集1.1.1IP收集1.1.2端口收集1.1.3目录收集 1.2 webs…

SQL错题集2

1.插入记录 用户1001在2021年9月1日晚上10点11分12秒开始作答试卷9001&#xff0c;并在50分钟后提交&#xff0c;得了90分&#xff1b; 用户1002在2021年9月4日上午7点1分2秒开始作答试卷9002&#xff0c;并在10分钟后退出了平台。 2.请把exam_record表中2021年9月1日之前开始作…

连接池 Druid (二) - 连接回收 DestroyThread

接上一篇文章&#xff0c;研究Druid连接池的连接回收线程DestroyThread&#xff0c;通过调用destroyTask.run->DruidDataSourcek.shrink完成过期连接的回收。 DruidDataSourcek.shrink 理解DruidDataSourcek的连接回收方法shrink有一个必要前提&#xff1a;Druid的getConn…

离散数学-函数

1、函数的概念 1&#xff09;函数定义 定义&#xff1a;设 x &#xff0c; y是集合&#xff0c;f是x到y的二元关系&#xff0c;若对每个x属于X&#xff0c;都有唯一的y属于Y&#xff0c;使得<x,y>属于f&#xff0c;则称f是x到y的函数或映射&#xff0c;记作&#xff1a…

在vscode编辑器中,vetur和volar冲突

在vscode编辑器中 vetur插件会把vue3项目当成vue2去检查&#xff0c;然后出现了eslint报错 在项目的 package.json 中添加以下代码&#xff0c;并重启编辑器就可以了 // package.json"eslintConfig": {"rules": {"vue/no-multiple-template-root&qu…

深入理解CopyOnWriteArrayList源码分析

上篇推荐&#xff1a;Java中快速失败 (fail-fast) 机制 CopyOnWriteArrayList简介 CopyOnWriteArrayList是java.util.concurrent包下提供的一个线程安全的ArrayList。它通过一个简单的策略来保证线程安全&#xff1a;当我们需要修改列表时&#xff08;增加、删除、修改等操作&…

102 cesium 切换底图为黑色

1.切换cesium底图为黑色 // 底图const baseLayer viewer.imageryLayers.get(0);if (baseLayer.show) {baseLayer.show false;viewer.scene.globe.baseColor Cesium.Color.BLACK;} else {baseLayer.show true;} 2.地下模式 async toggleUnderground(item: any) {item.activ…

电子学会C/C++编程等级考试2023年03月(四级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:最佳路径 如下所示的由正整数数字构成的三角形: 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最…

Linux之重谈文件和c语言文件接口

重谈文件 文件 内容 属性, 所有对文件的操作都是: a.对内容操作 b.对属性操作 关于文件 一&#xff1a; 即使文件的内容为空&#xff0c;该文件也会在磁盘上也会占空间&#xff0c;因为文件不仅仅只有内容还有文件对应的属性&#xff0c;文件的内容会占用空间, 文件的属性也…

gitlab 迁移-安装-还原

文章目录 一、备份原有Gitlab1、备份清单2、备份执行 二、卸载删除原有Gitlab1、停止Gitlab2、卸载Gitlab3、查看Gitlab进程4、杀死进程5、删除所有包含Gitlab文件 三、安装Gitlab1、添加镜像地址2、安装依赖3、安装防火墙4、下载安装Gitlab5、配置Gitlab6、启动并访问 四、还原…

Linux基本指令(2.0)

周边知识&#xff1a; 1.Linux中&#xff0c; 一切皆文件 构建大文件 输入如下shell命令 i1; while [ $i -le 10000]; do echo "hello Linux $i"; let i; done 此时大文件已经创建在big.txt 此时我们发现cat查看无法查看开始内容 我们使用more 当占满一屏之后就不…