gpt4 book ai didi

c++ - 为什么基类析构函数调用免费

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:21:23 26 4
gpt4 key购买 nike

我正在为内存非常有限的 NIOS II 内核编译 C++ 程序。由于它是一个嵌入式系统,我们也不使用堆。由于我们将继承添加到我们的代码中,我们看到 malloc 和 free(以及相关函数)被构建到我们的二进制文件中,从而增加了它的大小千字节。

我们有一个纯虚基类 StatisticsApi 和一个派生类 Statistics。统计数据,它们都定义了虚拟析构函数。

我们正在使用带有 fno-rtti 和 -fno_expections 的 Alteras GCC 进行编译,并且还定义了我们自己的 __cxa_pure_virtual()

仔细观察我们发现 delete 是从析构函数中调用的(因此是免费的)。这是为什么?它试图释放什么内存?

这里是析构函数的汇编器:

0000c6b8 <_ZN7Namespace12StatisticsD0Ev>:
c6b8: defffd04 addi sp,sp,-12
c6bc: dfc00215 stw ra,8(sp)
c6c0: df000115 stw fp,4(sp)
c6c4: df000104 addi fp,sp,4
c6c8: e13fff15 stw r4,-4(fp)
c6cc: 00c000b4 movhi r3,2
c6d0: 18c74b04 addi r3,r3,7468
c6d4: e0bfff17 ldw r2,-4(fp)
c6d8: 10c00015 stw r3,0(r2)
c6dc: e13fff17 ldw r4,-4(fp)
c6e0: 000c7f00 call c7f0 <_ZN7Namespace15StatisticsApiD2Ev>
c6e4: 00800044 movi r2,1
c6e8: 10803fcc andi r2,r2,255
c6ec: 1005003a cmpeq r2,r2,zero
c6f0: 1000021e bne r2,zero,c6fc <_ZN7LinCtrl12TxStatisticsD0Ev+0x44>
c6f4: e13fff17 ldw r4,-4(fp)
c6f8: 000c8e00 call c8e0 <_ZdlPv>
c6fc: e037883a mov sp,fp
c700: dfc00117 ldw ra,4(sp)
c704: df000017 ldw fp,0(sp)
c708: dec00204 addi sp,sp,8
c70c: f800283a ret


0000c710 <_ZN7Namespace12StatisticsD1Ev>:
c710: defffd04 addi sp,sp,-12
c714: dfc00215 stw ra,8(sp)
c718: df000115 stw fp,4(sp)
c71c: df000104 addi fp,sp,4
c720: e13fff15 stw r4,-4(fp)
c724: 00c000b4 movhi r3,2
c728: 18c74b04 addi r3,r3,7468
c72c: e0bfff17 ldw r2,-4(fp)
c730: 10c00015 stw r3,0(r2)
c734: e13fff17 ldw r4,-4(fp)
c738: 000c7f00 call c7f0 <_ZN7Namespace15StatisticsApiD2Ev>
c73c: 0005883a mov r2,zero
c740: 10803fcc andi r2,r2,255
c744: 1005003a cmpeq r2,r2,zero
c748: 1000021e bne r2,zero,c754 <_ZN7Namespace12StatisticsD1Ev+0x44>
c74c: e13fff17 ldw r4,-4(fp)
c750: 000c8e00 call c8e0 <_ZdlPv>
c754: e037883a mov sp,fp
c758: dfc00117 ldw ra,4(sp)
c75c: df000017 ldw fp,0(sp)
c760: dec00204 addi sp,sp,8
c764: f800283a ret


0000c768 <_ZN7Namespace12StatisticsD2Ev>:
c768: defffd04 addi sp,sp,-12
c76c: dfc00215 stw ra,8(sp)
c770: df000115 stw fp,4(sp)
c774: df000104 addi fp,sp,4
c778: e13fff15 stw r4,-4(fp)
c77c: 00c000b4 movhi r3,2
c780: 18c74b04 addi r3,r3,7468
c784: e0bfff17 ldw r2,-4(fp)
c788: 10c00015 stw r3,0(r2)
c78c: e13fff17 ldw r4,-4(fp)
c790: 000c7f00 call c7f0 <_ZN7Namespace15StatisticsApiD2Ev>
c794: 0005883a mov r2,zero
c798: 10803fcc andi r2,r2,255
c79c: 1005003a cmpeq r2,r2,zero
c7a0: 1000021e bne r2,zero,c7ac <_ZN7Namespace12StatisticsD2Ev+0x44>
c7a4: e13fff17 ldw r4,-4(fp)
c7a8: 000c8e00 call c8e0 <_ZdlPv>
c7ac: e037883a mov sp,fp
c7b0: dfc00117 ldw ra,4(sp)
c7b4: df000017 ldw fp,0(sp)
c7b8: dec00204 addi sp,sp,8
c7bc: f800283a ret

下面是基类的析构函数:

0000c7f0 <_ZN7Namespace15StatisticsApiD2Ev>:
c7f0: defffd04 addi sp,sp,-12
c7f4: dfc00215 stw ra,8(sp)
c7f8: df000115 stw fp,4(sp)
c7fc: df000104 addi fp,sp,4
c800: e13fff15 stw r4,-4(fp)
c804: 00c000b4 movhi r3,2
c808: 18c76204 addi r3,r3,7560
c80c: e0bfff17 ldw r2,-4(fp)
c810: 10c00015 stw r3,0(r2)
c814: 0005883a mov r2,zero
c818: 10803fcc andi r2,r2,255
c81c: 1005003a cmpeq r2,r2,zero
c820: 1000021e bne r2,zero,c82c <_ZN7Namespace15StatisticsApiD2Ev+0x3c>
c824: e13fff17 ldw r4,-4(fp)
c828: 000c8e00 call c8e0 <_ZdlPv>
c82c: e037883a mov sp,fp
c830: dfc00117 ldw ra,4(sp)
c834: df000017 ldw fp,0(sp)
c838: dec00204 addi sp,sp,8
c83c: f800283a ret


0000c840 <_ZN7LinCtrl15TxStatisticsApiD0Ev>:
c840: defffd04 addi sp,sp,-12
c844: dfc00215 stw ra,8(sp)
c848: df000115 stw fp,4(sp)
c84c: df000104 addi fp,sp,4
c850: e13fff15 stw r4,-4(fp)
c854: 00c000b4 movhi r3,2
c858: 18c76204 addi r3,r3,7560
c85c: e0bfff17 ldw r2,-4(fp)
c860: 10c00015 stw r3,0(r2)
c864: 00800044 movi r2,1
c868: 10803fcc andi r2,r2,255
c86c: 1005003a cmpeq r2,r2,zero
c870: 1000021e bne r2,zero,c87c <_ZN7Namespace15StatisticsApiD0Ev+0x3c>
c874: e13fff17 ldw r4,-4(fp)
c878: 000c8e00 call c8e0 <_ZdlPv>
c87c: e037883a mov sp,fp
c880: dfc00117 ldw ra,4(sp)
c884: df000017 ldw fp,0(sp)
c888: dec00204 addi sp,sp,8
c88c: f800283a ret


0000c890 <_ZN7Namespace15StatisticsApiD1Ev>:
c890: defffd04 addi sp,sp,-12
c894: dfc00215 stw ra,8(sp)
c898: df000115 stw fp,4(sp)
c89c: df000104 addi fp,sp,4
c8a0: e13fff15 stw r4,-4(fp)
c8a4: 00c000b4 movhi r3,2
c8a8: 18c76204 addi r3,r3,7560
c8ac: e0bfff17 ldw r2,-4(fp)
c8b0: 10c00015 stw r3,0(r2)
c8b4: 0005883a mov r2,zero
c8b8: 10803fcc andi r2,r2,255
c8bc: 1005003a cmpeq r2,r2,zero
c8c0: 1000021e bne r2,zero,c8cc <_ZN7Namespace15StatisticsApiD1Ev+0x3c>
c8c4: e13fff17 ldw r4,-4(fp)
c8c8: 000c8e00 call c8e0 <_ZdlPv>
c8cc: e037883a mov sp,fp
c8d0: dfc00117 ldw ra,4(sp)
c8d4: df000017 ldw fp,0(sp)
c8d8: dec00204 addi sp,sp,8
c8dc: f800283a ret

最后删除:

0000c8e0 <_ZdlPv>:
c8e0: 20000126 beq r4,zero,c8e8 <_ZdlPv+0x8>
c8e4: 000ebf01 jmpi ebf0 <free>
c8e8: f800283a ret

这里是 NIOS II 指令集的链接以供引用:http://www.altera.com/literature/hb/nios2/n2cpu_nii51017.pdf

我们找到的两个解决方案/解决方法是:

  1. 将 new/delete 重新定义为空函数(没有堆,所以它们不应该无论如何都会被调用!)从而避免调用 free。

  2. 在 C++ 中保留未定义的析构函数,这使得它们无法获取在汇编程序中实例化。虽然编译器会提示没有虚拟析构函数。

解决方法与否,为什么析构函数调用免费?它试图释放什么内存!?!我们还有其他既不用于基类也不用于派生类的析构函数,它们不调用 free。这是这样一个析构函数的样子:

00005194 <_ZN7Namespace16OtherClassD2Ev>:
5194: defffe04 addi sp,sp,-8
5198: df000115 stw fp,4(sp)
519c: df000104 addi fp,sp,4
51a0: e13fff15 stw r4,-4(fp)
51a4: e037883a mov sp,fp
51a8: df000017 ldw fp,0(sp)
51ac: dec00104 addi sp,sp,4
51b0: f800283a ret

000051b4 <_ZN7Namespace16OtherClassD1Ev>:
51b4: defffe04 addi sp,sp,-8
51b8: df000115 stw fp,4(sp)
51bc: df000104 addi fp,sp,4
51c0: e13fff15 stw r4,-4(fp)
51c4: e037883a mov sp,fp
51c8: df000017 ldw fp,0(sp)
51cc: dec00104 addi sp,sp,4
51d0: f800283a ret

而且,一般来说,为什么每个析构函数(D0、D1 和 D2)都有多个函数?

最佳答案

当您使用虚拟析构函数对对象调用 delete 时,它​​会在虚拟表中查找要调用的函数。该函数调用析构函数并释放内存,因为只有在派生级别它才知道传递给自由函数的正确指针。

问题在于编译器不知道您从未调用 delete。它仍然必须创建代码,即使它可能永远不会被使用,就像任何其他虚函数一样。

尽管作为一般规则,析构函数在具有其他虚函数的类中应该是虚的,但这可能是一个有效的异常(exception)。使析构函数在基类中受到保护将有助于避免错误。

关于c++ - 为什么基类析构函数调用免费,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25745983/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com