面向对象编程(C++篇3)——析构
1. 概述
类的析构函数执行与构造函数相反的操作,当对象结束其生命周期,程序就会自动执行析构函数:
class ImageEx
{
public:
ImageEx()
{
cout << "Execute the constructor!" << endl;
}
~ImageEx()
{
cout << "Execute the destructor!" << endl;
}
};
int main()
{
ImageEx imageEx;
return 0;
}
那么同样的问题来了,为什么要有析构函数呢?
2. 详论
2.1. 对象生命周期
在经典C++中,需要通过new/delete来手动管理动态内存。如果我们在类中申请一个动态数组,并且通过自定义的函数Release()来释放它:
class ImageEx
{
public:
ImageEx()
{
cout << "Execute the constructor!" << endl;
data = new unsigned char[10];
}
~ImageEx()
{
cout << "Execute the destructor!" << endl;
}
void Release()
{
delete[] data;
data = nullptr;
}
private:
unsigned char * data;
};
int main()
{
{
ImageEx imageEx;
imageEx.Release();
}
return 0;
}
那么,当类对象离开作用域,结束生命周期之前,就必须显示调用一次成员函数Release(),否则就会造成内存泄漏:对象在调用析构函数之后,只会销毁数据成员data本身,而不是其指向的内存。
那么,一个合理的实现是,将成员函数Release()放入到析构函数:
class ImageEx
{
public:
ImageEx()
{
cout << "Execute the constructor!" << endl;
data = new unsigned char[10];
}
~ImageEx()
{
Release();
cout << "Execute the destructor!" << endl;
}
private:
unsigned char * data;
void Release()
{
delete[] data;
data = nullptr;
}
};
int main()
{
{
ImageEx imageEx;
}
return 0;
}
这样,当类对象离开作用域,结束生命周期之前,就自动通过析构函数,实现了动态数组的释放。好处是显而易见的:实现了类似于内置数据类型对象的生命周期管理,我们可以像使用内置数据类型对象一样使用类对象。这也体现了前文《面向对象编程(C++篇1)——引言》中提到的设计原则:类是抽象的自定义数据类型。
2.2. 不一定需要显式析构
在一些现代高级编程语言(C#、Java、Javascript)中,已经不用去手动管理动态内存,取而代之的,是其与操作系统的中间件(.net,jvm,浏览器)的GC(垃圾回收)机制。而在现代C++中,提倡通过智能指针(std::shared_ptr、std::unique_ptr、std::weak_ptr)来管理动态内存;对于动态数组,则使用标准容器std::vector则更好。在两者的内部都实现了前文提到的对象生命周期管理,在离开作用域后,通过析构函数自动释放管理的内存,无需再手动进行回收。
那么,一个显而易见的推论就出来了,如果我们在类中使用智能指针或者vector容器来替代new/delete管理动态内存,是不是就可以不用析构函数了?严格来说,是不用显式使用析构函数:
class ImageEx
{
public:
ImageEx():
data(10)
{
cout << "Execute the constructor!" << endl;
}
private:
std::vector<unsigned char> data;
};
int main()
{
ImageEx imageEx;
return 0;
}
实际上,并不是这个类不存在析构函数,而是编译器会为它生成一个合成的析构函数,在这个析构函数体中,什么也不用做。因为类中的动态内存,已经交由std::vector容器来管理。当类对象离开作用域调用析构函数之后,会销毁这个std::vector容器数据成员,进而触发其析构函数,释放其管理的内存。
2.3. 析构的必要性
根据上一节内容,不一定需要显式析构。因为现代C++的一些机制能够帮你自动管理动态内存。但是析构函数还是必要的,这是由于C++语言本身的性质决定的。作为C语言大部分内容的超集,需要兼容C语言手动管理内存的特性。更重要的是,现代操作系统几乎全部由C语言编写,与底层的交互不可避免的需要手动使用动态内存管理。
3. 总结
所以我们就能理解了,C++这门语言的设计哲学就是就是这样:既想要C语言的高性能,也想要高级语言高度抽象的特性。如果我们必须兼容C语言底层设计,那我们最好使用析构函数释放动态内存;否则多数情况下,我们应该使用智能指针或者stl容器来管理动态内存,从而避免显示使用析构函数。
面向对象编程(C++篇3)——析构的更多相关文章
- 面向对象编程(C++篇4)——RAII
目录 1. 概述 2. 详论 2.1. 堆.栈.静态区 2.2. 手动管理资源的弊端 2.3. 间接使用 2.4. 自下而上的抽象 3. 总结 4. 参考 1. 概述 在前面两篇文章<面向对象编 ...
- Python 第六篇(中):面向对象编程中级篇
面向对象编程中级篇: 编程思想概述: 面向过程:根据业务逻辑从上到下写垒代码 #最low,淘汰 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 #混口饭吃 def add(ho ...
- 面向对象编程(C++篇2)——构造
目录 1. 引述 2. 详述 2.1. 数据类型初始化 2.2. 类初始化 1. 引述 在C++中,学习类的第一课往往就是构造函数.根据构造函数的定义,构造函数式是用于初始化类对象的数据成员的.无论何 ...
- 面向对象编程(C++篇1)——引言
目录 1. 概述 2. 详论 2.1. 类与对象 2.2. 数据类型 3. 目录 1. 概述 现代C++与最原始的版本已经差不多是两种不同的语言了.不断发展的C++标准给C++这门语言带来了更多的范式 ...
- Python 第六篇(上):面向对象编程初级篇
面向:过程.函数.对象: 面向过程:根据业务逻辑从上到下写垒代码! 面向过程的编程弊:每次调用的时候都的重写,代码特别长,代码重用性没有,每次增加新功能所有的代码都的修改!那有什么办法解决上面出现的弊 ...
- python - 面向对象编程(初级篇)
写了这么多python 代码,也常用的类和对象,这里准备系统的对python的面向对象编程做以下介绍. 面向对象编程(Object Oriented Programming,OOP,面向对象程序设计) ...
- 面向对象编程-终结篇 es6新增语法
各位,各位,终于把js完成了一个段落了,这次的章节一过我还没确定下面要学的内容可能是vue也可能是前后端交互,但无论是哪个都挺兴奋的,因为面临着终于可以做点看得过去的大点的案例项目了,先憋住激动地情绪 ...
- 洗礼灵魂,修炼python(41)--巩固篇—从游戏《绝地求生-大逃杀》中回顾面向对象编程
声明:本篇文章仅仅以游戏<绝地求生>作为一个参考话题来介绍面向对象编程,只是作为学术引用,其制作的非常简易的程序也不会作为商业用途,与蓝洞公司无关. <绝地求生>最近很火,笼络 ...
- 学习Pytbon第十七篇,面向对象编程
面向对象技术简介 类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 类变量:类变量在整个实例化的对象中是公用的.类变量定义在类 ...
随机推荐
- markdown常见问题
图片的引用问题:  为啥不显示图片?????? 解答:图片路径不支持中文 斜体跟加粗 *强调* 或者 _强调_ (示例:斜体) **加重强调** ...
- cmd中删除、添加、修改注册表命令
转自:http://www.jb51.net/article/30586.htm regedit的运行参数 REGEDIT [/L:system] [/R:user] filename1 REGEDI ...
- 分布式消息队列RocketMQ(一)安装与启动
分布式消息队列RocketMQ 一.RocketMQ简介 RocketMQ(火箭MQ) 出自于阿里,后开源给apache成为apache的顶级开源项目之一,顶住了淘宝10年的 双11压力 是电商产品的 ...
- Solution -「ZJOI 2020」「洛谷 P6631」序列
\(\mathcal{Description}\) Link. 给定一个长为 \(n\) 的非负整数序列 \(\lang a_n\rang\),你可以进行如下操作: 取 \([l,r]\),将 ...
- My97DatePicker接口
复制于http://blog.csdn.net/lidew521/article/details/8531685 一. 简介 1. 简介 目前的版本是:4.2 正式版 发布于2008-12-03 2. ...
- IPMI日常使用
重启ipmi: ipmitool mc reset <warm|cold> warm表示软重启: cold表示硬重启: 设置IPMI地址: ipmitool lan set 1 i ...
- Mybatis的介绍和基本使用
巨人的肩膀 Mybatis的介绍和基本使用(1) (qq.com) Mybatis SQL映射文件详解(2) (qq.com)
- 非对称加解密 Asymmetric encryption 对称加密和非对称加密的区别
考虑这样一个问题:一切的装备文件都存储在 Git 长途库房,RAR密码破解装备文件中的一些信息又是比较灵敏的.所以,我们需求对这些灵敏信息进行加密处理.首要的加密方法分为两种:一种是同享密钥加 密(对 ...
- 入职钉钉接近半年,谈谈自身的新人landing体会
一.适应新环境 到了一个新环境里,身边的一切都比较陌生,与同事和领导都不太熟,一开始说话说不到一起都比较正常.在和同事吃饭的时候,多听多参与聊天,主动一些,逐渐熟悉起来就好了. 另外,我的工作台bas ...
- 前端点击png透明部分解决方案
看效果:点击空白区域红色1.点击实体区域红色2.分别得到颜色数据(包括透明度数据),控制台蓝色1.2.根据颜色数据即可解决png透明部分的点击问题. 让图片不能点击,分两种 1. 整张图片不能点击.这 ...