查看下面代码如何出错

#include <iostream>
using namespace std;
class A
{
public:
A()
{
p = this;
}
~A()
{
if (p!=NULL)
{
delete p;
p = NULL;
}
}
private:
A *p;
}; int main()
{
A a;
return ;
}
类的成员函数中能不能调用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,形成无限递归,造成堆栈溢出,系统崩溃。
--------------------我是分界面--------------------
上面是某大牛的分析,而在实际的运行过程中使用delele this确实会直接出现错误。这是因为:在成员函数中调用delete this,首先会调用类的析构函数,this指针已删除,会出现指针错误。
下面是在XCode中使用delete this出现的错误:
malloc: *** error for object 0xbffffa18: pointer being freed was not allocated
//注意0xbffffa18即为this的地址
*** set a breakpoint in malloc_error_break to debug
而在VS2010中使用delete this是直接导致 Debug Assertion Failed!
具体的描述是:invalid null pointer
总结:在成员函数中调用delete this,会导致指针错误,而在析构函数中调用delete this,出导致死循环,造成堆栈溢出
PS:this是类中成员函数具有的一个附加的隐含形参,即指向该类对象的一个指针,它与调用成员函数的对象绑定在一起。同时1.在普通的非const成员函数中:this的类型是一个指向类类型的const指针,可以改变this指向的值,但是不能改变this所保存的地址;2.在const成员函数中,this的类型是一个指向const类类型对象的const指针,既不能改变this所指向的对象,也不能改变this所保存的地址。
注意:
成员函数中不能定义this形参,而是由编译器隐含地定义,但是可以在成员函数中显示使用this形参,不过也不是必须这么做。如果对类成员的引用没有限定,编译器会将这种引用处理成通过this指针的引用。
有一种情况下必须显式使用this:当我们需要将一个对象作为整体引用而不是引用对象的一个成员时。
从const成员函数返回*this:不能从const成员函数返回指向类对象的普通引用。const成员函数只能返回*this作为一个const引用。

析构中delete this的更多相关文章

  1. C++不能中断构造函数来拒绝产生对象(在构造和析构中抛出异常)

    这是我的感觉,具体需要研究一下- 找到一篇文章:在构造和析构中抛出异常 测试验证在类构造和析构中抛出异常, 是否会调用该类析构. 如果在一个类成员函数中抛异常, 可以进入该类的析构函数. /// @f ...

  2. 对象析构谈—— delete this 的使用及注意事项

    this对象是必须是用 new操作符分配的(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象): delete this后,不能访问该对象任何的成员变量及 ...

  3. MYSQL中delete删除多表数据

    MYSQL中delete删除多表数据 DELETE删除多表数据,怎样才能同时删除多个关联表的数据呢?这里做了深入的解释: 1. delete from t1 where 条件 2.delete t1 ...

  4. C++ 中 delete 和 delete[] 的区别

    一直对 C++ 中 delete 和 delete[] 的区别不甚了解,今天遇到了,上网查了一下,得出了结论.做个备份,以免丢失. C++ 告诉我们在回收用 new 分配的单个对象的内存空间时用 de ...

  5. vim中delete(backspace)键不能向左删除

    MacOS修改为英文语言之后,忽然出现如题问题:delete键不能向左删除,只可以删除本次插入模式下插入的文本.原因: 转载:https://www.smslit.top/2016/11/27/vim ...

  6. oracle中delete、truncate、drop的区别

    oracle中delete.truncate.drop的区别 标签: deleteoracletable存储 2012-05-23 15:12 7674人阅读 评论(0) 收藏 举报  分类: ora ...

  7. 请说明SQLServer中delete from tablea & truncate table tablea的区别

    请说明SQLServer中delete from tablea & truncate table tablea的区别 解答:两者都可以用来删除表中所有的记录.区别在于:truncate是DDL ...

  8. 【转】 C++中delete和delete[]的区别

    一直对C++中的delete和delete[]的区别不甚了解,今天遇到了,上网查了一下,得出了结论.做个备份,以免丢失. C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete ...

  9. C++中delete[]是如何知道数组大小的

    先看一段代码: int main(void) { int *pI = new int; int *pArray = new int[10]; int size = *(pArray-1); delet ...

随机推荐

  1. Python进阶:多线程、多进程和线程池编程/协程和异步io/asyncio并发编程

    gil: gil使得同一个时刻只有一个线程在一个CPU上执行字节码,无法将多个线程映射到多个CPU上执行 gil会根据执行的字节码行数以及时间片释放gil,gil在遇到io的操作时候主动释放 thre ...

  2. linux 修改系统字符集,查看字符

    修改系统字符集 # cd /etc/sysconfig # vi i18n -------------------文件内容------------------ LANG="zh_CN.GB1 ...

  3. SQL语言分类DDL、DML、DQL、TCL、DCL

    关系型数据库的SQL语句都可以分为4大类: 1. DDL(数据定义语言)     DDL 主要是指如下的四种SQL 语句,以 CREATE.DROP.ALRET开头和 TRUNCATE TABLE 语 ...

  4. Design:设计(活动)百科

    ylbtech-Design:设计(活动)百科 设计是把一种设想通过合理的规划.周密的计划.通过各种感觉形式传达出来的过程.人类通过劳动改造世界,创造文明,创造物质财富和精神财富,而最基础.最主要的创 ...

  5. Html5 学习笔记 --》布局

    不推荐: 浮动布局: footer 设置 clear : both 清理浮动 |  header            |  |边 |      | |内    |            内容     ...

  6. VMware虚拟机重新挂载共享目录

    经常遇到设置的共享目录在重启虚拟机后找不到的情况,于是写了个脚本:mount-shared-folders. 前提是你的虚拟机中已经安装了VMware的相关工具(一般装完虚拟机都会自动安装上的) #! ...

  7. leetcode.双指针.88合并两个有序数组-Java

    1. 具体题目 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 说明: 初始化 nums1 和 nums2 的元素数量分别 ...

  8. 再往DjVu鼓吹者的头上敲一棒子

    最近在某论坛又看到有人在鼓吹DjVu,甚至声称拿到PDG就转成DjVu,忍不住想再敲打敲打. 早几年前就已经有人举出过实例,证明PDG.TIFF转DjVu会因为有损压缩而产生错别字,似乎时间长了一堆新 ...

  9. SQLAlchemy应用到Flask中

    安装模块 pip install Flask-SQLAlchemy 加入Flask-SQLAlchemy第三方组件 from flask import Flask # 导入Flask-SQLAlche ...

  10. mybatis的缓存机制及用例介绍

    在实际的项目开发中,通常对数据库的查询性能要求很高,而mybatis提供了查询缓存来缓存数据,从而达到提高查询性能的要求. mybatis的查询缓存分为一级缓存和二级缓存,一级缓存是SqlSessio ...