深度剖析 C++ 析构函数

本贴最后更新于 2303 天前,其中的信息可能已经时移世易

构造函数和析构函数在 C++ 中意味着生命周期的开始和结束,它们的实现原理相同。由于析构函数往往还设置成虚函数,所以这里我重点介绍下 C++ 析构函数的原理和各种场景。
一、析构函数的作用
当对象的生命周期结束时,会自动调用析构函数,以清理一些资源,比如释放内存、关闭文件、关闭数据库连接等等。
二、析构函数调用的时机
(1)基类析构
4624d87b3bb64c79bff4bf5a7924c345.png
我们反汇编下查看上面代码:
526d15332d5b4763becae057a465c347.png
从反汇编中可以看出,在对象离开它的作用域时,编译器自动给我们添加了一个析构函数调用的语句。
那我们使用 new 产生的对象会什么时候调用析构函数呢,这里我们把 fun1 里对象改成动态生成。
void fun1()
{
Base *base = new Base();

cout<<"fun1 over"<<endl;
}
当我们不使用 delete 释放内存时,看反汇编的情况
8e129ee60b03423091ba459db2bacf52.png
此时,没有任何地方调用 Base 的析构函数
当我们使用 delete 释放对象时,
void fun1()
{
Base *base = new Base();

delete base;
cout<<"fun1 over"<<endl;
}
我们反汇编结果:
be6c9b24aa034331b5413629ea13b107.png
这里我们看到析构函数调用了,这是因为当我们使用 delete 删除对象时,编译器会自动在后面添加一条调用析构函数的语句;
从这里我们也可以看书,C++ 中的 new 和 delete 和 c 语言中 malloc 和 free 的唯一区别就是使用 new 和 delete 编译会自动添加一条调用构造
函数和析构函数的语句,其他作用一样,都是释放内存,所以我们在 C++ 中一定要是否 new 和 delete 操作内存,不然就没办法调用构造或
析构函数了
(2)派生类析构
前面分析的是基类的析构函数,那派生类对象析构时自身和基类的析构函数什么时候调用呢,这里我们添加一个派生类:
35acbecef8cf464f9f0f298c245cc40c.png
从上面的分析我们可以知道,编译器会给我们添加一个派生类的析构函数调用,我们分析下派生类的析构函数
68239ef1f5bf4c9684c1698955ac708f.png
我们可以看出,派生类析构函数执行完后会执行基类的构造函数,这说明编译器给派生类析构函数后面都会增加一个直接父类的析构函数调用的语句,
这样就能保证派生类的所有父类的析构函数都会调用。
三、为什么要将基类的析构函数设置为虚函数
这里我们将派生类的对象赋值给基类的引用
e36d199a1d1645d3a9440b66e5194c0f.png
这时候我们反汇编看析构函数的调用情况:
25d812bc5e024a09b7d5464a00d5a725.png
这里我们看到,编译器只给我添加了基类的析构函数调用,我们从上面分析指导,只有派生类的析构函数后面会添加父类的析构函数调用,而父类的析构函数
后面没有子类的析构函数调用,这就造成了派生类的析构函数没有调用,导致一些资源没有正常释放。
当我们把基类的析构函数设置为虚函数时,这时我们反汇编:
a28bd90edece4c5fa0f74308d0bb64d0.png
这个时候我们发现,编译器给我们添加调用的就不是一个具体的析构函数了,那我们调用的到底是哪个析构函数呢?
原来当我们将析构函数定义为虚函数的时候,编译器就会为每个对象添加一个虚表,保存着该对象实例类的虚函数指针(这里 Base 对象实例保存的就是 Base 类对应的析构函数指针,
Child 对象实例保存的就是 Child 类的析构函数指针)。这时编译器就不会静态为我们生成调用那个具体的析构函数,而时在运行的时候查找这种虚表,找到对应的调用地址,因为
我们这里是 Child 对象实例,因此调用的就是 Child 类的析构函数,从而保证派生类和父类的析构函数都会调用。
四、什么时候要将析构函数设为虚函数
将所有类设为虚函数好吗?从上面可以看出,设为虚函数后,类的对象实例会增加一个虚表,占用额外的内存空间,而且调用的时候会查表再调用,对程序的性能影响不好;所以,
在真实的开发环境中,只需将那些实现多态的类(将子类对象指向父类引用)的基类设为虚函数就行了,这样可以避免程序性能变差。

  • 程序员

    程序员是从事程序开发、程序维护的专业人员。

    586 引用 • 3538 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    143 引用 • 442 回帖
  • Flutter

    Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。 Flutter 可以与现有的代码一起工作,它正在被越来越多的开发者和组织使用,并且 Flutter 是完全免费、开源的。

    39 引用 • 92 回帖 • 1 关注
  • Notion

    Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

    10 引用 • 76 回帖
  • OneDrive
    2 引用 • 1 关注
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 109 关注
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 393 关注
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    91 引用 • 384 回帖 • 1 关注
  • 链书

    链书(Chainbook)是 B3log 开源社区提供的区块链纸质书交易平台,通过 B3T 实现共享激励与价值链。可将你的闲置书籍上架到链书,我们共同构建这个全新的交易平台,让闲置书籍继续发挥它的价值。

    链书社

    链书目前已经下线,也许以后还有计划重制上线。

    14 引用 • 257 回帖 • 2 关注
  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖 • 1 关注
  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1440 引用 • 10067 回帖 • 493 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    83 引用 • 37 回帖
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 233 回帖 • 2 关注
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 642 关注
  • JetBrains

    JetBrains 是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄国的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是 Java 编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA

    18 引用 • 54 回帖 • 2 关注
  • Google

    Google(Google Inc.,NASDAQ:GOOG)是一家美国上市公司(公有股份公司),于 1998 年 9 月 7 日以私有股份公司的形式创立,设计并管理一个互联网搜索引擎。Google 公司的总部称作“Googleplex”,它位于加利福尼亚山景城。Google 目前被公认为是全球规模最大的搜索引擎,它提供了简单易用的免费服务。不作恶(Don't be evil)是谷歌公司的一项非正式的公司口号。

    49 引用 • 192 回帖
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 205 关注
  • ZooKeeper

    ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 HBase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

    59 引用 • 29 回帖 • 3 关注
  • 安全

    安全永远都不是一个小问题。

    203 引用 • 818 回帖 • 1 关注
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 646 关注
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 662 关注
  • DevOps

    DevOps(Development 和 Operations 的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。

    57 引用 • 25 回帖 • 9 关注
  • 酷鸟浏览器

    安全 · 稳定 · 快速
    为跨境从业人员提供专业的跨境浏览器

    3 引用 • 59 回帖 • 46 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    186 引用 • 318 回帖 • 258 关注
  • gRpc
    11 引用 • 9 回帖 • 89 关注
  • 游戏

    沉迷游戏伤身,强撸灰飞烟灭。

    180 引用 • 821 回帖