返回信息流面试的时候被问到一道题:一个基类和一个子类,基类的析构函数非虚,子类有一个int b成员,main()里面new一个子类对象,用基类指针指向它,delete基类指针会造成子类的成员b内存泄漏吗?
当时我想的是非虚的析构函数不会析构子类成员,所以b会造成内存泄漏,但是面试官说b不是动态申请的内存,会在main()函数之后被析构掉,所以不会造成内存泄漏,这种说法貌似是没问题的,实测了一下编译器没有抛出异常,但是如果把int b换成一个成员对象Data,基类的析构函数仍然非虚,实测发现子类和Data的析构函数都没有输出(打断点发现没有执行析构函数),如下图,但是也没有抛出异常,没有析构Data但也没有内存泄漏,想问下大佬这是咋回事啊?测试平台VS2019_v142,C++17,x86
这是一条镜像帖。来源:北邮人论坛 / cpp / #101842同步于 2022/4/25
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
【问题】关于非虚析构函数是否存在内存泄漏的问题
brz222
2022/4/25镜像同步19 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
【 在 brz222 的大作中提到: 】
: 面试的时候被问到一道题:一个基类和一个子类,基类的析构函数非虚,子类有一个int b成员,main()里面new一个子类对象,用基类指针指向它,delete基类指针会造成子类的成员b内存泄漏吗?
: 当时我想的是非虚的析构函数不会析构子类成员,所以b会造成内存泄漏,但是面试官说b不是动态申请的内存,会在main()函数之后被析构掉,所以不会造成内存泄漏,这种说法貌似是没问题的,实测了一下编译器没有抛出异常,但是如果把int b换成一个成员对象Data,基类的析构函数仍然非虚,实测发现子类和Data的析构函数都没有输出(打断点发现没有执行析构函数),如下图,但是也没有抛出异常,没有析构Data但也没有内存泄漏,想问下大佬这是咋回事啊?测试平台VS2019_v142,C++17,x86
:
[upload=1][/upload]
delete会把整个对象释放掉。基类指针指向子类对象,delete基类指针会把整个对象都释放掉。
即使没有调用子类的delete,但是也把子类空间释放了。
若子类额外申请了内存,那么这片内存不会被释放,因为没有调用子类的析构函数。
这个应该不是编译期确定的吧,之前看侯捷的视频,new的时候才会将内存的大小存起来
【 在 shuidi 的大作中提到: 】
: delete如何确定要释放多少字节呢?这个在编译时期就确定了,这个释放的长度信息在头部中保存。
: 个人理解是这样的
个人觉得面试官说的应该没有问题.
1.new derive的时候会按照derive类的大小来申请动态内存,delete的时候会根据申请的大小(这个数值应该会存在分配空间的头部)来进行释放,若子类中只有一个data类型,这个数据并不是动态分配的,则delete p的时候,整块内存都会回收,不存在内存泄露.
2.至于没有调用derive的析构函数,是因为delete p,p是指向base类型的,然而base类型并没有虚析构函数,则编译器应该会直接调用base的析构函数,跳过derive的.但是由于derive里面的数据成员是data,其实也没有什么影响,若derive里面的是成员是data*,指向动态分配的内存,按照图中写的析构方式则会造成内存泄露,泄露的是data*指向的那一部分内存.
3.另外内存泄露是不会抛出异常的,只会导致当前进程的可用内存空间变小.引用非法的内存地址(解引用一个已经释放的内存地址)才会触发异常.检测内存泄露有一些好用的工具,比如valgrind
【 在 shuidi 的大作中提到: 】
: delete会把整个对象释放掉。基类指针指向子类对象,delete基类指针会把整个对象都释放掉。
: 即使没有调用子类的delete,但是也把子类空间释放了。
: 若子类额外申请了内存,那么这片内存不会被释放,因为没有调用子类的析构函数。
受教了,非常感谢。
受教了,非常感谢
【 在 a912655391 的大作中提到: 】
: 个人觉得面试官说的应该没有问题.
: 1.new derive的时候会按照derive类的大小来申请动态内存,delete的时候会根据申请的大小(这个数值应该会存在分配空间的头部)来进行释放,若子类中只有一个data类型,这个数据并不是动态分配的,则delete p的时候,整块内存都会回收,不存在内存泄露.
: 2.至于没有调用derive的析构函数,是因为delete p,p是指向base类型的,然而base类型并没有虚析构函数,则编译器应该会直接调用base的析构函数,跳过derive的.但是由于derive里面的数据成员是data,其实也没有什么影响,若derive里面的是成员是data*,指向动态分配的内存,按照图中写的析构方式则会造成内存泄露,泄露的是data*指向的那一部分内存.
: ...................
class里面的malloc/new才需要调用析构去free/delete,如果没有就不需要,new的时候会给你分配class成员变量大概这么大小的内存,如果有一些变量是pointer,那么需要为这些pointer进行alloc和free的就是class本身的逻辑,main里面delete也只会回收当时给你分配的那些内存,class里面的pointer分配的需要class的析构去回收(这个时候才需要虚析构)