类成员函数调用delete this会发生什么呢?
有如下代码
class myClass
{
public:
myClass(){};
~myClass(){};
void foo()
{
delete this;
}
};
int main()
{
myClass * aa = new myClass();
aa->foo();
return 0;
}
会发生什么呢?
在类的成员函数中能不能调用delete this?答案是肯定的,能调用,而且很多老一点的库都有这种代码。假设这个成员函数名字叫release,而delete this就在这个release方法中被调用,那么这个对象在调用release方法后,还能进行其他操作,如调用该对象的其他方法么?答案仍然是肯定 的,调用release之后还能调用其他的方法,但是有个前提:被调用的方法不涉及这个对象的数据成员和虚函数。说到这里,相信大家都能明白为什么会这样 了。
根本原因在于delete操作符的功能和类对象的内存模型。当一个类对象声明时,系统会为其分配内存空间。在类对象的内存空间中,只有数据成员和虚函数表指针,并不包含代码内容,类的成员函数单独放在代码段中。在调用成员函数时,隐含传递一个this指针,让成员函数知道当前是哪个对象在调用它。当 调用delete this时,类对象的内存空间被释放。在delete this之后进行的其他任何函数调用,只要不涉及到this指针的内容,都能够正常运行。一旦涉及到this指针,如操作数据成员,调用虚函数等,就会出现不可预期的问题。
为什么是不可预期的问题?delete this之后不是释放了类对象的内存空间了么,那么这段内存应该已经还给系统,不再属于这个进程。照这个逻辑来看,应该发生指针错误,无访问权限之类的令系统崩溃的问题才对啊?这个问题牵涉到操作系统的内存管理策略。delete this释放了类对象的内存空间,但是内存空间却并不是马上被回收到系统中,可能是缓冲或者其他什么原因,导致这段内存空间暂时并没有被系统收回。此时这段内存是可以访问的,你可以加上100,加上200,但是其中的值却是不确定的。当你获取数据成员,可能得到的是一串很长的未初始化的随机数;访问虚函数表,指针无效的可能性非常高,造成系统崩溃。
大致明白在成员函数中调用delete this会发生什么之后,再来看看另一个问题,如果在类的析构函数中调用delete this,会发生什么?实验告诉我们,会导致堆栈溢出。原因很简单,delete的本质是“为将被释放的内存调用一个或多个析构函数,然后,释放内存” (来自effective c++)。显然,delete this会去调用本对象的析构函数,而析构函数中又调用delete this,形成无限递归,造成堆栈溢出,系统崩溃。
类成员函数调用delete this会发生什么呢?的更多相关文章
- C++并发类成员函数调用(练习1)
一般类成员函数开线程格式 std::thread t1(&类名::函数,&实例化对象,参数....) ||std::thread t1(std::bind(&&类名:: ...
- C++类成员空间分配和虚函数表
最近在自学python,看到继承和类,就顺便复习了C++的类和继承等方面的知识. 先看Base基类 class Base { private: virtual void display() { cou ...
- C/C++基础----特殊工具和技术 (重载new和delete,RTT,限定作用域的枚举类型,类成员指针,嵌套类,局部类,volatile,链接指示 extern “C”)
重载new和delete 1调用operator new( 或new[])标准库函数分配足够大的.原始的.未命名的内存空间以便存储特定类型的对象 2编译器运行相应地构造函数以构造这些对象,并为其传入初 ...
- 直接调用类成员函数地址(用汇编取类成员函数的地址,各VS版本还有所不同)
在C++中,成员函数的指针是个比较特殊的东西.对普通的函数指针来说,可以视为一个地址,在需要的时候可以任意转换并直接调用.但对成员函数来说,常规类型转换是通不过编译的,调用的时候也必须采用特殊的语法. ...
- python 面向对象和类成员和异常处理
python 面向对象 你把自己想象成一个上帝,你要创造一个星球,首先你要把它揉成一个个球,两个直径就能创造一个球 class star: '''名字(name),赤道直径(equatorial di ...
- python的类和对象——类成员番外篇
学完了面向对象的三大特性,已经get了所有屌丝技能的我们也当一回文艺小青年,来看看类的成员和成员修饰符. 今天‘三’这个数字好亲和~~~类成员可以分为三类:字段.方法和属性 一.字段 首先我们来看看字 ...
- Objective-C类成员变量深度剖析
目录 Non Fragile ivars 为什么Non Fragile ivars很关键 如何寻址类成员变量 真正的“如何寻址类成员变量” Non Fragile ivars布局调整 为什么Objec ...
- C++学习46 getline()函数读入一行字符 一些与输入有关的istream类成员函数
getline函数的作用是从输入流中读取一行字符,其用法与带3个参数的get函数类似.即 cin.getline(字符数组(或字符指针), 字符个数n, 终止标志字符) [例13.7] 用get ...
- ### C++总结-[类成员函数]
C++类中的常见函数. #@author: gr #@date: 2015-07-23 #@email: forgerui@gmail.com 一.constructor, copy construc ...
随机推荐
- redis5集群搭建步骤
通常情况下为了redis的高可用,我们一般不会使用redis的单实例去运行,一般都会搭建一个 redis 的集群去运行.此处记录一下 redis5 以后 cluster 集群的搭建. 一.需求 red ...
- Noip模拟69 2021.10.5
考场拼命$yy$高精度结果没学好$for$循环痛失$50pts$,当场枯死 以后一定打对拍,要不考后会... T1 石子游戏 首先要知道典型的$NIM$博弈,就是说如果所有堆石子个数的异或和为$0$则 ...
- QEvent
QEvent类是所有事件类的基类,每一个对象都包含事件参数.Qt的主事件循环(QCoreApplication::exec())从事件队列中接收本地窗口系统的事件,并将它们翻译成QEvent,将这些事 ...
- STM32入门-STM32时钟系统,时钟初始化配置函数
在前面推文的介绍中,我们知道STM32系统复位后首先进入SystemInit函数进行时钟的设置,然后进入主函数main.那么我们就来看下SystemInit()函数到底做了哪些操作,首先打开我们前面使 ...
- 并发编程从零开始(十二)-Lock与Condition
并发编程从零开始(十二)-Lock与Condition 8 Lock与Condition 8.1 互斥锁 8.1.1 锁的可重入性 "可重入锁"是指当一个线程调用 object.l ...
- js实现日期格式化封装--八种
封装一个momentTime.js文件,包含8种格式. 需要传两个参数: 时间戳:stamp 格式化的类型:type, 日期补零的方法用到es6语法中的padStart(length,'字符'): 第 ...
- 【接口】SpringBoot+接口开发(一)
一.接口的简单介绍 1.什么是接口:接口及服务: 2.接口的分类:(1)系统的内部接口;(2)第三方的外部接口; 3.简述接口原理图: 4.接口协议:是指客户端跟服务器之间或者接口与接口间进行的通讯时 ...
- 【java+selenium3】自动化截图 (十四)
一.截图 1. Firefox浏览器截图 FirefoxDriver firefoxDriver = new FirefoxDriver(); firefoxDriver.getScreenshotA ...
- SQL注入之猫舍
第一步:先查看是否存在注入点:构造?id=1 and 1=1 回车后发现页面正常 构造?id=1 and 1=2 发现页面异常,得出结论:存在注入点 第二步:判断字段数 当输入order by 1和o ...
- elementUI下拉框select组件change事件用法
<el-select-custom clearable collapse-tags v-model="searchForm.cardTypeList" @change=&qu ...